From a399839bdc8ee6b5198f59ed2391d24680f51589 Mon Sep 17 00:00:00 2001 From: Raz Ben Simon Date: Wed, 22 Sep 2021 18:22:54 +0300 Subject: [PATCH] fix gitlab_project_id changes every apply (#145) * fix gitlab_project_id changes every apply * fix broken test * add test * fix docs --- README.md | 6 +- env0/resource_template.go | 2 +- env0/resource_template_test.go | 126 +++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 185847a1..039e84f1 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ provider "env0" { ### Run local version of the provider - Build - `./build.sh` - Create the plugins folder - `mkdir -p ~/.terraform.d/plugins/terraform.env0.com/local/env0/6.6.6/darwin_amd64` -- Copy the built binary - `cp ~/env0/terraform-provider-env0/terraform-provider-env0 ~/.terraform.d/plugins/terraform.env0.com/local/env0/6.6.6/darwin_amd64` (Replace `darwin` with `linux` on Linux) +- Copy the built binary - `cp ./terraform-provider-env0 ~/.terraform.d/plugins/terraform.env0.com/local/env0/6.6.6/darwin_amd64` (Replace `darwin` with `linux` on Linux) - Require the local provider in your `main.tf` - ``` terraform { @@ -132,12 +132,12 @@ go generate ./... ## Documentation - Docs are generated using github.com/hashicorp/terraform-plugin-docs -- Run `./generate-docs` to generate docs +- Run `./generate-docs.sh` to generate docs - Must be run manually before releasing a version ## Release To release a version to the [Terraform Public Registry](https://registry.terraform.io/providers/env0/env0/latest?pollNotifications=true) - -1. Docs must be generated manually and committed to the repo before release. (`./generate-docs`) +1. Docs must be generated manually and committed to the repo before release. (`./generate-docs.sh`) 2. Create and push a tag locally, in semver format - `git tag v0.0.9 && git push origin --tags` 3. Goto [Github Releases](https://github.com/env0/terraform-provider-env0/releases) and edit the draft created by Release Drafter Bot - it should contain the change log for the release. Make sure it's pointing at the tag you created in the previous step and publish the release. 4. Binaries will be automatically generated by the Github action defined in `.github/workflows/release.yml` diff --git a/env0/resource_template.go b/env0/resource_template.go index bcadaf34..69a86e93 100644 --- a/env0/resource_template.go +++ b/env0/resource_template.go @@ -243,12 +243,12 @@ func resourceTemplateRead(ctx context.Context, d *schema.ResourceData, meta inte d.Set("description", template.Description) d.Set("github_installation_id", template.GithubInstallationId) d.Set("token_id", template.TokenId) - d.Set("gitlab_project_id", template.GitlabProjectId) d.Set("repository", template.Repository) d.Set("path", template.Path) d.Set("revision", template.Revision) d.Set("type", template.Type) d.Set("terraform_version", template.TerraformVersion) + // 'gitlab_project_id' should not be set because it doesn't exist on 'template' var rawSshKeys []map[string]string for _, sshKey := range template.SshKeys { diff --git a/env0/resource_template_test.go b/env0/resource_template_test.go index 4a6d94df..91365198 100644 --- a/env0/resource_template_test.go +++ b/env0/resource_template_test.go @@ -18,6 +18,52 @@ func TestUnitTemplateResource(t *testing.T) { var resourceFullName = resourceAccessor(resourceType, resourceName) + fullTemplateResourceConfig := func(resourceType string, resourceName string, template client.Template) string { + templateAsDictionary := map[string]interface{}{ + "name": template.Name, + "repository": template.Repository, + } + + if template.Type != "" { + templateAsDictionary["type"] = template.Type + } + if template.Description != "" { + templateAsDictionary["description"] = template.Description + } + if template.Revision != "" { + templateAsDictionary["revision"] = template.Revision + } + if template.Path != "" { + templateAsDictionary["path"] = template.Path + } + if template.Retry != (client.TemplateRetry{}) && template.Retry.OnDeploy != nil { + templateAsDictionary["retries_on_deploy"] = template.Retry.OnDeploy.Times + if template.Retry.OnDeploy.ErrorRegex != "" { + templateAsDictionary["retry_on_deploy_only_when_matches_regex"] = template.Retry.OnDeploy.ErrorRegex + } + } + if template.Retry != (client.TemplateRetry{}) && template.Retry.OnDestroy != nil { + templateAsDictionary["retries_on_destroy"] = template.Retry.OnDestroy.Times + if template.Retry.OnDestroy.ErrorRegex != "" { + templateAsDictionary["retry_on_destroy_only_when_matches_regex"] = template.Retry.OnDestroy.ErrorRegex + } + } + if template.TerraformVersion != "" { + templateAsDictionary["terraform_version"] = template.TerraformVersion + } + if template.TokenId != "" { + templateAsDictionary["token_id"] = template.TokenId + } + if template.GitlabProjectId != 0 { + templateAsDictionary["gitlab_project_id"] = template.GitlabProjectId + } + if template.GithubInstallationId != 0 { + templateAsDictionary["github_installation_id"] = template.GithubInstallationId + } + + return resourceConfigCreate(resourceType, resourceName, templateAsDictionary) + } + t.Run("Full Github template (without SSH keys)", func(t *testing.T) { template := client.Template{ Id: "id0", @@ -80,23 +126,6 @@ func TestUnitTemplateResource(t *testing.T) { ) } - fullTemplateResourceConfig := func(resourceType string, resourceName string, template client.Template) string { - return resourceConfigCreate(resourceType, resourceName, map[string]interface{}{ - "name": template.Name, - "description": template.Description, - "repository": template.Repository, - "path": template.Path, - "revision": template.Revision, - "type": template.Type, - "retries_on_deploy": template.Retry.OnDeploy.Times, - "retry_on_deploy_only_when_matches_regex": template.Retry.OnDeploy.ErrorRegex, - "retries_on_destroy": template.Retry.OnDestroy.Times, - "retry_on_destroy_only_when_matches_regex": template.Retry.OnDestroy.ErrorRegex, - "github_installation_id": template.GithubInstallationId, - "terraform_version": template.TerraformVersion, - }) - } - testCase := resource.TestCase{ Steps: []resource.TestStep{ { @@ -208,24 +237,6 @@ func TestUnitTemplateResource(t *testing.T) { ) } - fullTemplateResourceConfig := func(resourceType string, resourceName string, template client.Template) string { - return resourceConfigCreate(resourceType, resourceName, map[string]interface{}{ - "name": template.Name, - "description": template.Description, - "repository": template.Repository, - "path": template.Path, - "revision": template.Revision, - "type": template.Type, - "retries_on_deploy": template.Retry.OnDeploy.Times, - "retry_on_deploy_only_when_matches_regex": template.Retry.OnDeploy.ErrorRegex, - "retries_on_destroy": template.Retry.OnDestroy.Times, - "retry_on_destroy_only_when_matches_regex": template.Retry.OnDestroy.ErrorRegex, - "token_id": template.TokenId, - "gitlab_project_id": template.GitlabProjectId, - "terraform_version": template.TerraformVersion, - }) - } - testCase := resource.TestCase{ Steps: []resource.TestStep{ { @@ -483,15 +494,18 @@ func TestUnitTemplateResource(t *testing.T) { Steps: []resource.TestStep{ { Config: resourceConfigCreate(resourceType, resourceName, map[string]interface{}{"name": "test", "repository": "env0/test", regexAttribute: "bla"}), - ExpectError: regexp.MustCompile(fmt.Sprintf("`%s,%s` must be specified", timesAttribute, regexAttribute)), + ExpectError: regexp.MustCompile(fmt.Sprintf("`%s,%s`\\s+must\\s+be\\s+specified", timesAttribute, regexAttribute)), }, }, }) } + for _, testCase := range testCases { + runUnitTest(t, testCase, func(mockFunc *client.MockApiClientInterface) {}) + } }) - t.Run("Gitlab and Github template", func(t *testing.T) { + t.Run("Mixed Gitlab and Github template", func(t *testing.T) { var testCases []resource.TestCase testCases = append(testCases, resource.TestCase{ @@ -507,4 +521,42 @@ func TestUnitTemplateResource(t *testing.T) { runUnitTest(t, testCase, func(mockFunc *client.MockApiClientInterface) {}) } }) + + t.Run("Should not trigger terraform changes when gitlab_project_id is provided", func(t *testing.T) { + template := client.Template{ + Id: "id0", + Name: "template0", + Repository: "env0/repo", + Type: "terraform", + GitlabProjectId: 123456, + TokenId: "abcdefg", + TerraformVersion: defaultVersion, + } + + tfConfig := fullTemplateResourceConfig(resourceType, resourceName, template) + var testCase = resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: tfConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceFullName, "gitlab_project_id", strconv.Itoa(template.GitlabProjectId)), + ), + }, + { + PlanOnly: true, + ExpectNonEmptyPlan: false, + Config: tfConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceFullName, "gitlab_project_id", strconv.Itoa(template.GitlabProjectId)), + ), + }, + }, + } + + runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) { + mock.EXPECT().Template(template.Id).Times(3).Return(template, nil) // 1 after create, 1 before update, 1 after update + mock.EXPECT().TemplateCreate(gomock.Any()).Times(1).Return(template, nil) + mock.EXPECT().TemplateDelete(template.Id).Times(1).Return(nil) + }) + }) }