-
Notifications
You must be signed in to change notification settings - Fork 708
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Github Environments Policy feature causing the provider to produ…
…ce inconsistent result (#1799) * Add deployment policy resource - Add the initial code to manage the resource - Add sample configuration used to test it TODO - Documentation - Tests * Add schema description * Fix creation of resource ID * Add tests * Add documentation * Add terraform import support * Undo example add * Fix formatting * PR feedback * fix: environment branch policy failing to find the created resource The `Read` operation of the Environments Branch Policy resource was failing to find the newly created Branch policies, due to wrongly encoded environment name. Which cause the provider to be inconsistent. This fix uses `url.PathEscape` instead of `url.QueryEscape` since we are using path parameters with the Github API in that case. Additionally 2 operations - `Read` and `Delete` don't need to use it as they receive the environment name already parsed and attempting to encode it again breaks the name. * Fix incorrect merge --------- Co-authored-by: Massimiliano Donini <massimiliano.donini@gmail.com> Co-authored-by: Keegan Campbell <me@kfcampbell.com>
- Loading branch information
1 parent
dc087bd
commit 64f123a
Showing
5 changed files
with
311 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
github/resource_github_repository_environment_deployment_policy.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
|
||
"github.com/google/go-github/v53/github" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
) | ||
|
||
func resourceGithubRepositoryEnvironmentDeploymentPolicy() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceGithubRepositoryEnvironmentDeploymentPolicyCreate, | ||
Read: resourceGithubRepositoryEnvironmentDeploymentPolicyRead, | ||
Update: resourceGithubRepositoryEnvironmentDeploymentPolicyUpdate, | ||
Delete: resourceGithubRepositoryEnvironmentDeploymentPolicyDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
Schema: map[string]*schema.Schema{ | ||
"repository": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Description: "The name of the repository. The name is not case sensitive.", | ||
}, | ||
"environment": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Description: "The name of the environment.", | ||
}, | ||
"branch_pattern": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: false, | ||
Description: "The name pattern that branches must match in order to deploy to the environment.", | ||
}, | ||
}, | ||
} | ||
|
||
} | ||
|
||
func resourceGithubRepositoryEnvironmentDeploymentPolicyCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
ctx := context.Background() | ||
|
||
owner := meta.(*Owner).name | ||
repoName := d.Get("repository").(string) | ||
envName := d.Get("environment").(string) | ||
branchPattern := d.Get("branch_pattern").(string) | ||
escapedEnvName := url.PathEscape(envName) | ||
|
||
createData := github.DeploymentBranchPolicyRequest{ | ||
Name: github.String(branchPattern), | ||
} | ||
|
||
resultKey, _, err := client.Repositories.CreateDeploymentBranchPolicy(ctx, owner, repoName, escapedEnvName, &createData) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(buildThreePartID(repoName, escapedEnvName, strconv.FormatInt(resultKey.GetID(), 10))) | ||
return resourceGithubRepositoryEnvironmentDeploymentPolicyRead(d, meta) | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentDeploymentPolicyRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
ctx := context.WithValue(context.Background(), ctxId, d.Id()) | ||
|
||
owner := meta.(*Owner).name | ||
repoName, envName, branchPolicyIdString, err := parseThreePartID(d.Id(), "repository", "environment", "branchPolicyId") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
branchPolicyId, err := strconv.ParseInt(branchPolicyIdString, 10, 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
branchPolicy, _, err := client.Repositories.GetDeploymentBranchPolicy(ctx, owner, repoName, envName, branchPolicyId) | ||
if err != nil { | ||
if ghErr, ok := err.(*github.ErrorResponse); ok { | ||
if ghErr.Response.StatusCode == http.StatusNotModified { | ||
return nil | ||
} | ||
if ghErr.Response.StatusCode == http.StatusNotFound { | ||
log.Printf("[INFO] Removing branch deployment policy for %s/%s/%s from state because it no longer exists in GitHub", | ||
owner, repoName, envName) | ||
d.SetId("") | ||
return nil | ||
} | ||
} | ||
return err | ||
} | ||
|
||
d.Set("branch_pattern", branchPolicy.GetName()) | ||
return nil | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentDeploymentPolicyUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
ctx := context.Background() | ||
|
||
owner := meta.(*Owner).name | ||
repoName := d.Get("repository").(string) | ||
envName := d.Get("environment").(string) | ||
branchPattern := d.Get("branch_pattern").(string) | ||
escapedEnvName := url.PathEscape(envName) | ||
_, _, branchPolicyIdString, err := parseThreePartID(d.Id(), "repository", "environment", "branchPolicyId") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
branchPolicyId, err := strconv.ParseInt(branchPolicyIdString, 10, 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
updateData := github.DeploymentBranchPolicyRequest{ | ||
Name: github.String(branchPattern), | ||
} | ||
|
||
resultKey, _, err := client.Repositories.UpdateDeploymentBranchPolicy(ctx, owner, repoName, escapedEnvName, branchPolicyId, &updateData) | ||
if err != nil { | ||
return err | ||
} | ||
d.SetId(buildThreePartID(repoName, escapedEnvName, strconv.FormatInt(resultKey.GetID(), 10))) | ||
return resourceGithubRepositoryEnvironmentDeploymentPolicyRead(d, meta) | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentDeploymentPolicyDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
ctx := context.Background() | ||
|
||
owner := meta.(*Owner).name | ||
repoName, envName, branchPolicyIdString, err := parseThreePartID(d.Id(), "repository", "environment", "branchPolicyId") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
branchPolicyId, err := strconv.ParseInt(branchPolicyIdString, 10, 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = client.Repositories.DeleteDeploymentBranchPolicy(ctx, owner, repoName, envName, branchPolicyId) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
89 changes: 89 additions & 0 deletions
89
github/resource_github_repository_environment_deployment_policy_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package github | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource" | ||
) | ||
|
||
func TestAccGithubRepositoryEnvironmentDeploymentPolicy(t *testing.T) { | ||
|
||
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) | ||
|
||
t.Run("creates a repository environment with deployment policy", func(t *testing.T) { | ||
|
||
config := fmt.Sprintf(` | ||
data "github_user" "current" { | ||
username = "" | ||
} | ||
resource "github_repository" "test" { | ||
name = "tf-acc-test-%s" | ||
} | ||
resource "github_repository_environment" "test" { | ||
repository = github_repository.test.name | ||
environment = "environment/test" | ||
wait_timer = 10000 | ||
reviewers { | ||
users = [data.github_user.current.id] | ||
} | ||
deployment_branch_policy { | ||
protected_branches = false | ||
custom_branch_policies = true | ||
} | ||
} | ||
resource "github_repository_environment_deployment_policy" "test" { | ||
repository = github_repository.test.name | ||
environment = github_repository_environment.test.environment | ||
branch_pattern = "releases/*" | ||
} | ||
`, randomID) | ||
|
||
check := resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr( | ||
"github_repository_environment_deployment_policy.test", "repository", | ||
fmt.Sprintf("tf-acc-test-%s", randomID), | ||
), | ||
resource.TestCheckResourceAttr( | ||
"github_repository_environment_deployment_policy.test", "environment", | ||
"environment/test", | ||
), | ||
resource.TestCheckResourceAttr( | ||
"github_repository_environment_deployment_policy.test", "branch_pattern", | ||
"releases/*", | ||
), | ||
) | ||
|
||
testCase := func(t *testing.T, mode string) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { skipUnlessMode(t, mode) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: config, | ||
Check: check, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
t.Run("with an anonymous account", func(t *testing.T) { | ||
t.Skip("anonymous account not supported for this operation") | ||
}) | ||
|
||
t.Run("with an individual account", func(t *testing.T) { | ||
testCase(t, individual) | ||
}) | ||
|
||
t.Run("with an organization account", func(t *testing.T) { | ||
testCase(t, organization) | ||
}) | ||
|
||
}) | ||
} |
60 changes: 60 additions & 0 deletions
60
website/docs/r/repository_environment_deployment_policy.html.markdown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
--- | ||
layout: "github" | ||
page_title: "GitHub: github_repository_environment_deployment_policy" | ||
description: |- | ||
Creates and manages environment deployment branch policies for GitHub repositories | ||
--- | ||
|
||
# github_repository_environment_deployment_policy | ||
|
||
This resource allows you to create and manage environment deployment branch policies for a GitHub repository. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
data "github_user" "current" { | ||
username = "" | ||
} | ||
resource "github_repository" "test" { | ||
name = "tf-acc-test-%s" | ||
} | ||
resource "github_repository_environment" "test" { | ||
repository = github_repository.test.name | ||
environment = "environment/test" | ||
wait_timer = 10000 | ||
reviewers { | ||
users = [data.github_user.current.id] | ||
} | ||
deployment_branch_policy { | ||
protected_branches = false | ||
custom_branch_policies = true | ||
} | ||
} | ||
resource "github_repository_environment_deployment_policy" "test" { | ||
repository = github_repository.test.name | ||
environment = github_repository_environment.test.environment | ||
branch_pattern = "releases/*" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `environment` - (Required) The name of the environment. | ||
|
||
* `repository` - (Required) The repository of the environment. | ||
|
||
* `branch_pattern` - (Required) The name pattern that branches must match in order to deploy to the environment. | ||
|
||
|
||
## Import | ||
|
||
GitHub Repository Environment Deployment Policy can be imported using an ID made up of `name` of the repository combined with the `environment` name of the environment with the `Id` of the deployment policy, separated by a `:` character, e.g. | ||
|
||
``` | ||
$ terraform import github_repository_environment.daily terraform:daily:123456 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters