Skip to content

Add github_repository_environment_deployment_protection_rule resource - #3566

Open
stockmaj wants to merge 11 commits into
integrations:mainfrom
stockmaj:dpr-6.13
Open

stockmaj wants to merge 11 commits into
integrations:mainfrom
stockmaj:dpr-6.13

Conversation

@stockmaj

@stockmaj stockmaj commented Jul 21, 2026 •

Copy link
Copy Markdown

Resolves #2225


Before the change?

  • The provider can't enable a GitHub App as a custom deployment protection rule on an environment, so that gate can only be set up in the UI or through the API.

After the change?

  • New resource github_repository_environment_deployment_protection_rule enables an App as a custom deployment protection rule on an environment, and disables it on destroy.
  • It follows github_repository_environment_deployment_policy: repository_id is tracked, so renaming the repository updates the resource in place, and pointing it at a different repository replaces it.
  • If the rule, environment or repository is already gone, the resource is removed from state rather than failing the destroy.
  • Acceptance tests look up an App that can be used as a protection rule on the test environment, and skip if none is available. I didn't add a new test setting. I ran the unit tests (Read, Update, Delete against the mock API), make test and make lintcheck. I haven't run the acceptance tests: my test account has no App that can be enabled as a protection rule. If the test org has one, the acceptance tests will cover create, import, rename and repository change.

Pull request checklist

  • Schema migrations have been created if needed (not needed: new resource)
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (for bug fixes / features)

Does this introduce a breaking change?

Please see our docs on breaking changes to help!

  • Yes
  • No

Enables a GitHub App as a custom deployment protection rule on an environment
(the deployment_protection_rule gate), which the provider previously could not
express declaratively — resolves integrations#2225.

CRUD + import over go-github's Create/Get/DisableCustomDeploymentProtectionRule;
schema is repository + environment + integration_id, mirroring the existing
github_repository_environment_deployment_policy resource. Based on v6.13.0.
@github-actions

Copy link
Copy Markdown

👋 Hi, and thank you for this contribution!

This repo is maintained by GitHub and community members on a best-effort basis. We'll get to this as soon as we can.

You can help us prioritize by joining the discussion on open issues and PRs, sharing details on the changes you need, and reviewing other contributions.


🤖 This is an automated message.

stockmaj and others added 4 commits July 22, 2026 09:23
InternalValidate rejects the resource: with no UpdateContext, every attribute
must be ForceNew. repository was Required-only. Mark it ForceNew and drop the
now-redundant diffRepository CustomizeDiff (it keys off a repository_id this
resource doesn't have). `go test -run TestProvider` (InternalValidate) passes.
main upgraded go-github v88 -> v89; the CreateCustomDeploymentProtectionRule
request type moved packages. Match the rest of the provider.
@@ -0,0 +1,67 @@
---

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation should be generated through templates after running make generatedocs.

I've tested locally and deleting it is actually not working.
I would expect the following templates:

  • templates/resources/repository_environment_deployment_protection_rule.md.tmpl
  • examples/resources/repository_environment_deployment_protection_rule/example_1.tf (usage)
  • examples/resources/repository_environment_deployment_protection_rule/example_2.tf (import block)

Look into templates/resources/repository_environment_deployment_policy.md.tmpl for example

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing tests resource_github_repository_environment_deployment_protection_rule_test.go with TestAccGithubRepositoryEnvironmentDeploymentProtectionRule

}
d.SetId(id)

return resourceGithubRepositoryEnvironmentDeploymentProtectionRuleRead(ctx, d, m)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/integrations/terraform-provider-github/blob/main/ARCHITECTURE.md#crud-function-signatures

// Never call Read at end of Create, set any Computed fields in Create

)

func resourceGithubRepositoryEnvironmentDeploymentProtectionRule() *schema.Resource {
return &schema.Resource{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This resource is missing a Description field used for the documentation generation

func resourceGithubRepositoryEnvironmentDeploymentProtectionRule() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"repository": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should have a computed repository_id to be resilient to repository name changes

rule, _, err := client.Repositories.GetCustomDeploymentProtectionRule(ctx, owner, repoName, url.PathEscape(envName), ruleID)
if err != nil {
var ghErr *github.ErrorResponse
if errors.As(err, &ghErr) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use errors.AsType*github.ErrorResponse instead

return diag.FromErr(err)
}
if rule.App != nil {
if err := d.Set("integration_id", int(rule.App.GetID())); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of error, this would keep the old value in state?

return diag.FromErr(fmt.Errorf("invalid rule id: %s", ruleIDStr))
}

_, err = client.Repositories.DisableCustomDeploymentProtectionRule(ctx, owner, repoName, url.PathEscape(envName), ruleID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should treat 404 as deleted

@acouvreur

Copy link
Copy Markdown
Contributor

@stockmaj let me know if you are willing to continue this pull request.

@stockmaj

Copy link
Copy Markdown
Author

@acouvreur Yes, I'm willing to continue this PR. I'll work through your review comments and push an update.

- Add a resource Description for docs generation.
- Add computed repository_id and use diffRepository so a repository
  rename updates the resource in place instead of replacing it; add an
  Update function that rebuilds the ID after a rename.
- Add computed protection_rule_id and read repository, environment and
  rule ID from state rather than parsing the resource ID.
- Set Computed fields in Create instead of calling Read.
- Use errors.AsType[*github.ErrorResponse] for error checks.
- Always set integration_id in Read so a stale value cannot stay in state.
- Treat a 404 on delete as already deleted, so destroy succeeds when the
  rule, environment or repository is already gone.
- Stop escaping the environment name: go-github v92 escapes it, so the
  extra url.PathEscape double-encoded names containing `/` or spaces.
Add TestAccGithubRepositoryEnvironmentDeploymentProtectionRule covering
create and delete (with a CheckDestroy that lists the environment's
rules), import, repository rename and repository change. The tests need
an App that can be enabled as a custom deployment protection rule, read
from GH_TEST_DEPLOYMENT_PROTECTION_RULE_APP_ID, and skip without it.

Add unit tests for Read and Delete against a mock API, covering 404
handling, the integration_id refresh and environment name escaping.
Replace the hand-written page with a template and examples rendered by
`make generatedocs`.
…ing one

The acceptance test lists the apps available as custom deployment protection
rules on the test environment and skips when there are none, so it needs no new
test configuration.
Update only rewrote the ID, so a repository change that diffRepository could
not resolve at plan time applied as a no-op and left the rule on the old
repository. Update now checks the new name still resolves to repository_id.

Also validate integration_id, skip the acceptance tests when the test
credentials cannot list protection rule apps, and list the resource in
RESOURCES.md.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT]: Add support for deployment protection rules

2 participants