From ac18f667c54ba98d2e60b1d2309f5ea24948b2c8 Mon Sep 17 00:00:00 2001 From: Jacob White Date: Mon, 5 Sep 2022 20:56:31 -0400 Subject: [PATCH 01/11] Add importer for pages projects --- .changelog/1886.txt | 3 ++ ..._resource_cloudflare_pages_project_test.go | 35 +++++++++++++++++ internal/provider/provider_test.go | 2 + .../resource_cloudflare_pages_project.go | 38 ++++++++++++++++++- .../resource_cloudflare_pages_project_test.go | 9 ++--- 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 .changelog/1886.txt create mode 100644 internal/provider/import_resource_cloudflare_pages_project_test.go diff --git a/.changelog/1886.txt b/.changelog/1886.txt new file mode 100644 index 0000000000..12d421b379 --- /dev/null +++ b/.changelog/1886.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/cloudflare_pages_project: Adds importer for pages_project +``` diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go new file mode 100644 index 0000000000..b57723c26d --- /dev/null +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -0,0 +1,35 @@ +package provider + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccCloudflarePagesProject_Import(t *testing.T) { + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + rnd := generateRandomResourceName() + name := fmt.Sprintf("cloudflare_pages_project.%s", rnd) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheckEmail(t) + testAccPreCheckApiKey(t) + }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: testPagesProjectDirectUpload(rnd, accountID), + }, + { + ResourceName: name, + ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"allow_overwrite"}, + }, + }, + }) +} diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index f0e23b0282..8368900d3e 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -161,6 +161,8 @@ func testAccPreCheckWorkspaceOne(t *testing.T) { } func testAccPreCheckPages(t *testing.T) { + testAccPreCheckAccount(t) + if v := os.Getenv("CLOUDFLARE_PAGES_OWNER"); v == "" { t.Fatal("CLOUDFLARE_PAGES_OWNER must be set for this acceptance test") } diff --git a/internal/provider/resource_cloudflare_pages_project.go b/internal/provider/resource_cloudflare_pages_project.go index d02ac225d0..6519cce524 100644 --- a/internal/provider/resource_cloudflare_pages_project.go +++ b/internal/provider/resource_cloudflare_pages_project.go @@ -3,6 +3,8 @@ package provider import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-log/tflog" + "strings" "time" "github.com/MakeNowJust/heredoc/v2" @@ -18,6 +20,9 @@ func resourceCloudflarePagesProject() *schema.Resource { ReadContext: resourceCloudflarePagesProjectRead, UpdateContext: resourceCloudflarePagesProjectUpdate, DeleteContext: resourceCloudflarePagesProjectDelete, + Importer: &schema.ResourceImporter{ + StateContext: resourceCloudflarePagesProjectImport, + }, Description: heredoc.Doc(` Provides a resource which manages Cloudflare Pages projects. `), @@ -170,7 +175,7 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD return diag.FromErr(fmt.Errorf("error reading cloudflare pages project %q: %w", projectName, err)) } - d.SetId(res.ID) + d.SetId(res.Name) d.Set("subdomain", res.SubDomain) d.Set("created_on", res.CreatedOn.Format(time.RFC3339)) d.Set("domains", res.Domains) @@ -217,3 +222,34 @@ func resourceCloudflarePagesProjectDelete(ctx context.Context, d *schema.Resourc } return nil } + +func resourceCloudflarePagesProjectImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client := meta.(*cloudflare.API) + + // split the id so we can look up + idAttr := strings.SplitN(d.Id(), "/", 2) + var accountID string + var projectName string + if len(idAttr) == 2 { + accountID = idAttr[0] + projectName = idAttr[1] + } else { + return nil, fmt.Errorf("invalid id %q specified, should be in format \"accountID/project-name\" for import", d.Id()) + } + + project, err := client.PagesProject(ctx, accountID, projectName) + if err != nil { + return nil, fmt.Errorf("Unable to find record with ID %q: %w", d.Id(), err) + } + + tflog.Info(ctx, fmt.Sprintf("Found project: %s", project.Name)) + + d.SetId(project.Name) + d.Set("name", project.Name) + d.Set("account_id", accountID) + d.Set("production_branch", project.ProductionBranch) + + resourceCloudflarePagesProjectRead(ctx, d, meta) + + return []*schema.ResourceData{d}, nil +} diff --git a/internal/provider/resource_cloudflare_pages_project_test.go b/internal/provider/resource_cloudflare_pages_project_test.go index d7a8317ce8..d706e64a4b 100644 --- a/internal/provider/resource_cloudflare_pages_project_test.go +++ b/internal/provider/resource_cloudflare_pages_project_test.go @@ -105,14 +105,14 @@ func testPagesProjectDeploymentConfig(resourceID, accountID, projectName string) `, resourceID, accountID, projectName) } -func testPagesProjectDirectUpload(resourceID, accountID, projectName string) string { +func testPagesProjectDirectUpload(resourceID, accountID string) string { return fmt.Sprintf(` resource "cloudflare_pages_project" "%[1]s" { account_id = "%[2]s" - name = "%[3]s" + name = "%[1]s" production_branch = "main" } - `, resourceID, accountID, projectName) + `, resourceID, accountID) } func testPagesProjectPreviewOnly(resourceID, accountID, projectName string) string { @@ -324,12 +324,11 @@ func TestAccTestPagesProject_DirectUpload(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccPreCheckPages(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: testPagesProjectDirectUpload(rnd, accountID, rnd), + Config: testPagesProjectDirectUpload(rnd, accountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", rnd), resource.TestCheckResourceAttr(name, "account_id", accountID), From f07f537bbc2848e47209f978183248a7d96d9499 Mon Sep 17 00:00:00 2001 From: Jacob White Date: Mon, 5 Sep 2022 20:59:38 -0400 Subject: [PATCH 02/11] Adds import example --- docs/resources/pages_project.md | 6 ++++++ examples/resources/cloudflare_pages_project/import.sh | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 examples/resources/cloudflare_pages_project/import.sh diff --git a/docs/resources/pages_project.md b/docs/resources/pages_project.md index c60aaf9b57..89a769b257 100644 --- a/docs/resources/pages_project.md +++ b/docs/resources/pages_project.md @@ -203,4 +203,10 @@ Optional: - `production_deployment_enabled` (Boolean) Enable production deployments. - `repo_name` (String) Project repository name. +## Import +Import is supported using the following syntax: +```shell +# Use account ID, and project name. +$ terraform import cloudflare_pages_project.example / +``` diff --git a/examples/resources/cloudflare_pages_project/import.sh b/examples/resources/cloudflare_pages_project/import.sh new file mode 100644 index 0000000000..e42d04ae52 --- /dev/null +++ b/examples/resources/cloudflare_pages_project/import.sh @@ -0,0 +1,2 @@ +# Use account ID, and project name. +$ terraform import cloudflare_pages_project.example / From 252e0fef16acdc3ae80e285bc7d7f350763b9aa1 Mon Sep 17 00:00:00 2001 From: Jacob White Date: Mon, 5 Sep 2022 21:06:58 -0400 Subject: [PATCH 03/11] Fix lint --- internal/provider/provider_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 8368900d3e..481accf155 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -162,7 +162,7 @@ func testAccPreCheckWorkspaceOne(t *testing.T) { func testAccPreCheckPages(t *testing.T) { testAccPreCheckAccount(t) - + if v := os.Getenv("CLOUDFLARE_PAGES_OWNER"); v == "" { t.Fatal("CLOUDFLARE_PAGES_OWNER must be set for this acceptance test") } From 1d569ab5a59212451a1b56627f7be2b43cd2c311 Mon Sep 17 00:00:00 2001 From: Jacob White Date: Wed, 7 Sep 2022 16:29:46 -0400 Subject: [PATCH 04/11] Commit latest --- ..._resource_cloudflare_pages_project_test.go | 5 +- .../resource_cloudflare_pages_project.go | 53 ++++++++++++++++--- .../resource_cloudflare_pages_project_test.go | 12 ++--- 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go index b57723c26d..1742a0d19b 100644 --- a/internal/provider/import_resource_cloudflare_pages_project_test.go +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -9,9 +9,9 @@ import ( ) func TestAccCloudflarePagesProject_Import(t *testing.T) { - accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") rnd := generateRandomResourceName() name := fmt.Sprintf("cloudflare_pages_project.%s", rnd) + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -21,14 +21,13 @@ func TestAccCloudflarePagesProject_Import(t *testing.T) { ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: testPagesProjectDirectUpload(rnd, accountID), + Config: testPagesProjectBuildConfig(rnd, accountID, rnd, "project_owner", "project_repo"), }, { ResourceName: name, ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allow_overwrite"}, }, }, }) diff --git a/internal/provider/resource_cloudflare_pages_project.go b/internal/provider/resource_cloudflare_pages_project.go index 6519cce524..9177ea8c03 100644 --- a/internal/provider/resource_cloudflare_pages_project.go +++ b/internal/provider/resource_cloudflare_pages_project.go @@ -107,7 +107,7 @@ func buildPagesProject(d *schema.ResourceData) cloudflare.PagesProject { if webAnalyticsTag, ok := d.GetOk("build_config.0.web_analytics_tag"); ok { buildConfig.WebAnalyticsTag = webAnalyticsTag.(string) } - if webAnalyticsToken, ok := d.GetOk("build_config.0.web_analytics_tag"); ok { + if webAnalyticsToken, ok := d.GetOk("build_config.0.web_analytics_token"); ok { buildConfig.WebAnalyticsToken = webAnalyticsToken.(string) } project.BuildConfig = buildConfig @@ -170,15 +170,54 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD accountID := d.Get("account_id").(string) projectName := d.Get("name").(string) - res, err := client.PagesProject(ctx, accountID, projectName) + project, err := client.PagesProject(ctx, accountID, projectName) if err != nil { return diag.FromErr(fmt.Errorf("error reading cloudflare pages project %q: %w", projectName, err)) } - d.SetId(res.Name) - d.Set("subdomain", res.SubDomain) - d.Set("created_on", res.CreatedOn.Format(time.RFC3339)) - d.Set("domains", res.Domains) + tflog.Debug(ctx, fmt.Sprintf("Cloudflare Pages Project Response: %#v", project)) + d.SetId(project.Name) + d.Set("subdomain", project.SubDomain) + d.Set("production_branch", project.ProductionBranch) + d.Set("account_id", accountID) + d.Set("domains", project.Domains) + if project.Source != nil { + source := []map[string]interface{}{} + source = append(source, map[string]interface{}{ + "type": project.Source.Type, + "config": []map[string]interface{}{ + { + "owner": project.Source.Config.Owner, + "repo_name": project.Source.Config.RepoName, + "production_branch": project.Source.Config.ProductionBranch, + "pr_comments_enabled": project.Source.Config.PRCommentsEnabled, + "deployments_enabled": project.Source.Config.DeploymentsEnabled, + "preview_branch_includes": project.Source.Config.PreviewBranchIncludes, + "preview_branch_excludes": project.Source.Config.PreviewBranchExcludes, + "preview_deployment_setting": project.Source.Config.PreviewDeploymentSetting, + }, + }, + }, + ) + d.Set("source", source) + } + emptyProjectBuildConfig := cloudflare.PagesProjectBuildConfig{} + if project.BuildConfig != emptyProjectBuildConfig { + buildConfig := []map[string]interface{}{} + buildConfig = append(buildConfig, map[string]interface{}{ + "build_command": project.BuildConfig.BuildCommand, + "destination_dir": project.BuildConfig.DestinationDir, + "root_dir": project.BuildConfig.RootDir, + "web_analytics_tag": project.BuildConfig.WebAnalyticsTag, + "web_analytics_token": project.BuildConfig.WebAnalyticsToken, + }, + ) + d.Set("build_config", buildConfig) + } + + + + d.Set("created_on", project.CreatedOn.Format(time.RFC3339)) return nil } @@ -244,10 +283,8 @@ func resourceCloudflarePagesProjectImport(ctx context.Context, d *schema.Resourc tflog.Info(ctx, fmt.Sprintf("Found project: %s", project.Name)) - d.SetId(project.Name) d.Set("name", project.Name) d.Set("account_id", accountID) - d.Set("production_branch", project.ProductionBranch) resourceCloudflarePagesProjectRead(ctx, d, meta) diff --git a/internal/provider/resource_cloudflare_pages_project_test.go b/internal/provider/resource_cloudflare_pages_project_test.go index d706e64a4b..25d574784e 100644 --- a/internal/provider/resource_cloudflare_pages_project_test.go +++ b/internal/provider/resource_cloudflare_pages_project_test.go @@ -177,7 +177,7 @@ func testPagesProjectProductionOnly(resourceID, accountID, projectName string) s `, resourceID, accountID, projectName) } -func TestAccTestPagesProject_Basic(t *testing.T) { +func TestAccCloudflarePagesProject_Basic(t *testing.T) { rnd := generateRandomResourceName() name := "cloudflare_pages_project." + rnd accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") @@ -218,7 +218,7 @@ func TestAccTestPagesProject_Basic(t *testing.T) { }) } -func TestAccTestPagesProject_BuildConfig(t *testing.T) { +func TestAccCloudflarePagesProject_BuildConfig(t *testing.T) { rnd := generateRandomResourceName() name := "cloudflare_pages_project." + rnd accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") @@ -248,7 +248,7 @@ func TestAccTestPagesProject_BuildConfig(t *testing.T) { }) } -func TestAccTestPagesProject_DeploymentConfig(t *testing.T) { +func TestAccCloudflarePagesProject_DeploymentConfig(t *testing.T) { rnd := generateRandomResourceName() name := "cloudflare_pages_project." + rnd accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") @@ -316,7 +316,7 @@ func TestAccTestPagesProject_DeploymentConfig(t *testing.T) { }) } -func TestAccTestPagesProject_DirectUpload(t *testing.T) { +func TestAccCloudflarePagesProject_DirectUpload(t *testing.T) { rnd := generateRandomResourceName() name := "cloudflare_pages_project." + rnd accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") @@ -339,7 +339,7 @@ func TestAccTestPagesProject_DirectUpload(t *testing.T) { }) } -func TestAccTestPagesProject_PreviewOnly(t *testing.T) { +func TestAccCloudflarePagesProject_PreviewOnly(t *testing.T) { rnd := generateRandomResourceName() name := "cloudflare_pages_project." + rnd accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") @@ -381,7 +381,7 @@ func TestAccTestPagesProject_PreviewOnly(t *testing.T) { }) } -func TestAccTestPagesProject_ProductionOnly(t *testing.T) { +func TestAccCloudflarePagesProject_ProductionOnly(t *testing.T) { rnd := generateRandomResourceName() name := "cloudflare_pages_project." + rnd accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") From afaa143a55e8ffdfebbf10f891ca3c6705043ecd Mon Sep 17 00:00:00 2001 From: Jacob White Date: Sun, 11 Sep 2022 19:43:47 -0400 Subject: [PATCH 05/11] Add parsing deployment configs --- ..._resource_cloudflare_pages_project_test.go | 153 +++++++++++++++++- .../resource_cloudflare_pages_project.go | 58 ++++++- 2 files changed, 206 insertions(+), 5 deletions(-) diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go index 1742a0d19b..ab9cc4f5f5 100644 --- a/internal/provider/import_resource_cloudflare_pages_project_test.go +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -8,10 +8,161 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) + +func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoName string) string { + return fmt.Sprintf(` + resource "cloudflare_pages_project" "%[1]s" { + account_id = "%[2]s" + name = "%[3]s" + production_branch = "main" + build_config { + build_command = "npm run build" + destination_dir = "build" + root_dir = "/" + web_analytics_tag = "" + web_analytics_token = "" + } + source { + type = "github" + config { + owner = "%[4]s" + repo_name = "%[5]s" + production_branch = "main" + pr_comments_enabled = true + deployments_enabled = true + production_deployment_enabled = true + preview_deployment_setting = "custom" + preview_branch_includes = ["dev","preview"] + preview_branch_excludes = ["main", "prod"] + + } + } + deployment_configs { + preview { + environment_variables = { + ENVIRONMENT = "preview" + } + kv_namespaces = { + KV_BINDING = "5eb63bbbe01eeed093cb22bb8f5acdc3" + } + durable_object_namespaces = { + DO_BINDING = "5eb63bbbe01eeed093cb22bb8f5acdc3" + } + r2_buckets = { + R2_BINDING = "some-bucket" + } + d1_databases = { + D1_BINDING = "445e2955-951a-4358-a35b-a4d0c813f63" + } + compatibility_date = "2022-08-15" + compatibility_flags = ["preview_flag"] + } + production { + environment_variables = { + ENVIRONMENT = "production" + OTHER_VALUE = "other value" + } + kv_namespaces = { + KV_BINDING_1 = "5eb63bbbe01eeed093cb22bb8f5acdc3" + KV_BINDING_2 = "3cdca5f8bb22bc390deee10ebbb36be5" + } + durable_object_namespaces = { + DO_BINDING_1 = "5eb63bbbe01eeed093cb22bb8f5acdc3" + DO_BINDING_2 = "3cdca5f8bb22bc390deee10ebbb36be5" + } + r2_buckets = { + R2_BINDING_1 = "some-bucket" + R2_BINDING_2 = "other-bucket" + } + d1_databases = { + D1_BINDING_1 = "445e2955-951a-4358-a35b-a4d0c813f63" + D1_BINDING_2 = "a399414b-c697-409a-a688-377db6433cd9" + } + compatibility_date = "2022-08-16" + compatibility_flags = ["production_flag", "second flag"] + } + } + } + `, resourceID, accountID, projectName, repoOwner, repoName) +} + +func testPagesProjectFullTEMP(resourceID, accountID, projectName, repoOwner, repoName string) string { + return fmt.Sprintf(` + resource "cloudflare_pages_project" "%[1]s" { + account_id = "%[2]s" + name = "%[3]s" + production_branch = "main" + build_config { + build_command = "npm run build" + destination_dir = "build" + root_dir = "/" + } + source { + type = "github" + config { + owner = "%[4]s" + repo_name = "%[5]s" + production_branch = "main" + pr_comments_enabled = true + deployments_enabled = true + production_deployment_enabled = false + preview_deployment_setting = "all" + preview_branch_includes = ["*"] + preview_branch_excludes = [] + + } + } + deployment_configs { + preview { + environment_variables = { + ENVIRONMENT = "preview" + } + kv_namespaces = { + KV_BINDING = "5eb63bbbe01eeed093cb22bb8f5acdc3" + } + durable_object_namespaces = { + DO_BINDING = "5eb63bbbe01eeed093cb22bb8f5acdc3" + } + r2_buckets = {} + d1_databases = { + D1_BINDING = "445e2955-951a-4358-a35b-a4d0c813f63" + } + compatibility_date = "2022-08-15" + compatibility_flags = ["preview_flag"] + } + production { + environment_variables = { + ENVIRONMENT = "production" + OTHER_VALUE = "other value" + } + kv_namespaces = { + KV_BINDING_1 = "5eb63bbbe01eeed093cb22bb8f5acdc3" + KV_BINDING_2 = "3cdca5f8bb22bc390deee10ebbb36be5" + } + durable_object_namespaces = { + DO_BINDING_1 = "5eb63bbbe01eeed093cb22bb8f5acdc3" + DO_BINDING_2 = "3cdca5f8bb22bc390deee10ebbb36be5" + } + r2_buckets = {} + d1_databases = { + D1_BINDING_1 = "445e2955-951a-4358-a35b-a4d0c813f63" + D1_BINDING_2 = "a399414b-c697-409a-a688-377db6433cd9" + } + compatibility_date = "2022-08-16" + compatibility_flags = ["production_flag", "second flag"] + } + } + } + `, resourceID, accountID, projectName, repoOwner, repoName) +} + func TestAccCloudflarePagesProject_Import(t *testing.T) { rnd := generateRandomResourceName() name := fmt.Sprintf("cloudflare_pages_project.%s", rnd) accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + pagesOwner := os.Getenv("CLOUDFLARE_PAGES_OWNER") + pagesRepo := os.Getenv("CLOUDFLARE_PAGES_REPO") + resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -21,7 +172,7 @@ func TestAccCloudflarePagesProject_Import(t *testing.T) { ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: testPagesProjectBuildConfig(rnd, accountID, rnd, "project_owner", "project_repo"), + Config: testPagesProjectFullTEMP(rnd, accountID, rnd, pagesOwner, pagesRepo), }, { ResourceName: name, diff --git a/internal/provider/resource_cloudflare_pages_project.go b/internal/provider/resource_cloudflare_pages_project.go index c6d7c5fa68..e9982dc8be 100644 --- a/internal/provider/resource_cloudflare_pages_project.go +++ b/internal/provider/resource_cloudflare_pages_project.go @@ -3,10 +3,12 @@ package provider import ( "context" "fmt" - "github.com/hashicorp/terraform-plugin-log/tflog" + "reflect" "strings" "time" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/MakeNowJust/heredoc/v2" "github.com/cloudflare/cloudflare-go" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -88,6 +90,46 @@ func buildDeploymentConfig(environment interface{}) cloudflare.PagesProjectDeplo return config } +func parseDeployementConfig(deployment cloudflare.PagesProjectDeploymentConfigEnvironment) (returnValue []map[string]interface{}) { + config := make(map[string]interface{}) + + config["compatibility_date"] = deployment.CompatibilityDate + config["compatibility_flags"] = deployment.CompatibilityFlags + + deploymentVars := map[string]string{} + for key, value := range deployment.EnvVars { + deploymentVars[key] = value.Value + } + config["environment_variables"] = deploymentVars + + deploymentVars = map[string]string{} + for key, value := range deployment.KvNamespaces { + deploymentVars[key] = value.Value + } + config["kv_namespaces"] = deploymentVars + + deploymentVars = map[string]string{} + for key, value := range deployment.DoNamespaces { + deploymentVars[key] = value.Value + } + config["durable_object_namespaces"] = deploymentVars + + deploymentVars = map[string]string{} + for key, value := range deployment.R2Bindings { + deploymentVars[key] = value.Name + } + config["r2_buckets"] = deploymentVars + + deploymentVars = map[string]string{} + for key, value := range deployment.D1Databases { + deploymentVars[key] = value.ID + } + config["d1_databases"] = deploymentVars + + returnValue = append(returnValue, config) + return +} + func buildPagesProject(d *schema.ResourceData) cloudflare.PagesProject { project := cloudflare.PagesProject{} project.Name = d.Get("name").(string) @@ -182,6 +224,8 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD d.Set("production_branch", project.ProductionBranch) d.Set("account_id", accountID) d.Set("domains", project.Domains) + d.Set("created_on", project.CreatedOn.Format(time.RFC3339)) + if project.Source != nil { source := []map[string]interface{}{} source = append(source, map[string]interface{}{ @@ -216,9 +260,15 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD d.Set("build_config", buildConfig) } - - - d.Set("created_on", project.CreatedOn.Format(time.RFC3339)) + emptyDeploymentConfig := cloudflare.PagesProjectDeploymentConfigs{} + if !reflect.DeepEqual(project.DeploymentConfigs, emptyDeploymentConfig) { + deploymentConfig := []map[string]interface{}{} + deploymentConfig = append(deploymentConfig, map[string]interface{}{ + "preview": parseDeployementConfig(project.DeploymentConfigs.Preview), + "production": parseDeployementConfig(project.DeploymentConfigs.Production), + }) + d.Set("deployment_configs", deploymentConfig) + } return nil } From 2e3320d561b6fffabba93f02579aba598c9ee218 Mon Sep 17 00:00:00 2001 From: Jacob White Date: Sun, 11 Sep 2022 20:06:36 -0400 Subject: [PATCH 06/11] Fix lint and remove temp test --- ..._resource_cloudflare_pages_project_test.go | 83 ++----------------- 1 file changed, 6 insertions(+), 77 deletions(-) diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go index ab9cc4f5f5..6f9a4e4698 100644 --- a/internal/provider/import_resource_cloudflare_pages_project_test.go +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -8,8 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) - -func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoName string) string { +func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoName string) string { return fmt.Sprintf(` resource "cloudflare_pages_project" "%[1]s" { account_id = "%[2]s" @@ -86,75 +85,6 @@ func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoNam `, resourceID, accountID, projectName, repoOwner, repoName) } -func testPagesProjectFullTEMP(resourceID, accountID, projectName, repoOwner, repoName string) string { - return fmt.Sprintf(` - resource "cloudflare_pages_project" "%[1]s" { - account_id = "%[2]s" - name = "%[3]s" - production_branch = "main" - build_config { - build_command = "npm run build" - destination_dir = "build" - root_dir = "/" - } - source { - type = "github" - config { - owner = "%[4]s" - repo_name = "%[5]s" - production_branch = "main" - pr_comments_enabled = true - deployments_enabled = true - production_deployment_enabled = false - preview_deployment_setting = "all" - preview_branch_includes = ["*"] - preview_branch_excludes = [] - - } - } - deployment_configs { - preview { - environment_variables = { - ENVIRONMENT = "preview" - } - kv_namespaces = { - KV_BINDING = "5eb63bbbe01eeed093cb22bb8f5acdc3" - } - durable_object_namespaces = { - DO_BINDING = "5eb63bbbe01eeed093cb22bb8f5acdc3" - } - r2_buckets = {} - d1_databases = { - D1_BINDING = "445e2955-951a-4358-a35b-a4d0c813f63" - } - compatibility_date = "2022-08-15" - compatibility_flags = ["preview_flag"] - } - production { - environment_variables = { - ENVIRONMENT = "production" - OTHER_VALUE = "other value" - } - kv_namespaces = { - KV_BINDING_1 = "5eb63bbbe01eeed093cb22bb8f5acdc3" - KV_BINDING_2 = "3cdca5f8bb22bc390deee10ebbb36be5" - } - durable_object_namespaces = { - DO_BINDING_1 = "5eb63bbbe01eeed093cb22bb8f5acdc3" - DO_BINDING_2 = "3cdca5f8bb22bc390deee10ebbb36be5" - } - r2_buckets = {} - d1_databases = { - D1_BINDING_1 = "445e2955-951a-4358-a35b-a4d0c813f63" - D1_BINDING_2 = "a399414b-c697-409a-a688-377db6433cd9" - } - compatibility_date = "2022-08-16" - compatibility_flags = ["production_flag", "second flag"] - } - } - } - `, resourceID, accountID, projectName, repoOwner, repoName) -} func TestAccCloudflarePagesProject_Import(t *testing.T) { rnd := generateRandomResourceName() @@ -163,7 +93,6 @@ func TestAccCloudflarePagesProject_Import(t *testing.T) { pagesOwner := os.Getenv("CLOUDFLARE_PAGES_OWNER") pagesRepo := os.Getenv("CLOUDFLARE_PAGES_REPO") - resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheckEmail(t) @@ -172,13 +101,13 @@ func TestAccCloudflarePagesProject_Import(t *testing.T) { ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: testPagesProjectFullTEMP(rnd, accountID, rnd, pagesOwner, pagesRepo), + Config: testPagesProjectFull(rnd, accountID, rnd, pagesOwner, pagesRepo), }, { - ResourceName: name, - ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), - ImportState: true, - ImportStateVerify: true, + ResourceName: name, + ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), + ImportState: true, + ImportStateVerify: true, }, }, }) From 679244042f0cdf450825b3a7278369d9d6f011f1 Mon Sep 17 00:00:00 2001 From: Jacob White Date: Sun, 11 Sep 2022 21:29:59 -0400 Subject: [PATCH 07/11] Switch to using d.ID() for page project resource --- ..._resource_cloudflare_pages_project_test.go | 1 - .../resource_cloudflare_pages_project.go | 20 +++++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go index 6f9a4e4698..aeaa8481b2 100644 --- a/internal/provider/import_resource_cloudflare_pages_project_test.go +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -85,7 +85,6 @@ func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoNam `, resourceID, accountID, projectName, repoOwner, repoName) } - func TestAccCloudflarePagesProject_Import(t *testing.T) { rnd := generateRandomResourceName() name := fmt.Sprintf("cloudflare_pages_project.%s", rnd) diff --git a/internal/provider/resource_cloudflare_pages_project.go b/internal/provider/resource_cloudflare_pages_project.go index e9982dc8be..5b3e1b636a 100644 --- a/internal/provider/resource_cloudflare_pages_project.go +++ b/internal/provider/resource_cloudflare_pages_project.go @@ -211,15 +211,13 @@ func buildPagesProject(d *schema.ResourceData) cloudflare.PagesProject { func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*cloudflare.API) accountID := d.Get("account_id").(string) - projectName := d.Get("name").(string) - project, err := client.PagesProject(ctx, accountID, projectName) + project, err := client.PagesProject(ctx, accountID, d.Id()) if err != nil { - return diag.FromErr(fmt.Errorf("error reading cloudflare pages project %q: %w", projectName, err)) + return diag.FromErr(fmt.Errorf("error reading cloudflare pages project %q: %w", d.Id(), err)) } tflog.Debug(ctx, fmt.Sprintf("Cloudflare Pages Project Response: %#v", project)) - d.SetId(project.Name) d.Set("subdomain", project.SubDomain) d.Set("production_branch", project.ProductionBranch) d.Set("account_id", accountID) @@ -278,24 +276,24 @@ func resourceCloudflarePagesProjectCreate(ctx context.Context, d *schema.Resourc accountID := d.Get("account_id").(string) pageProject := buildPagesProject(d) - _, err := client.CreatePagesProject(ctx, accountID, pageProject) + project, err := client.CreatePagesProject(ctx, accountID, pageProject) if err != nil { return diag.FromErr(fmt.Errorf("error creating cloudflare pages project %q: %w", pageProject.Name, err)) } + d.SetId(project.Name) return resourceCloudflarePagesProjectRead(ctx, d, meta) } func resourceCloudflarePagesProjectUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*cloudflare.API) accountID := d.Get("account_id").(string) - projectName := d.Get("name").(string) pageProject := buildPagesProject(d) - _, err := client.UpdatePagesProject(ctx, accountID, projectName, pageProject) + _, err := client.UpdatePagesProject(ctx, accountID, d.Id(), pageProject) if err != nil { - return diag.FromErr(fmt.Errorf("error updating cloudflare pages project %q: %w", pageProject.Name, err)) + return diag.FromErr(fmt.Errorf("error updating cloudflare pages project %q: %w", d.Id(), err)) } return resourceCloudflarePagesProjectRead(ctx, d, meta) @@ -304,11 +302,10 @@ func resourceCloudflarePagesProjectUpdate(ctx context.Context, d *schema.Resourc func resourceCloudflarePagesProjectDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*cloudflare.API) accountID := d.Get("account_id").(string) - projectName := d.Get("name").(string) - err := client.DeletePagesProject(ctx, accountID, projectName) + err := client.DeletePagesProject(ctx, accountID, d.Id()) if err != nil { - return diag.FromErr(fmt.Errorf("error deleting cloudflare pages project %q: %w", projectName, err)) + return diag.FromErr(fmt.Errorf("error deleting cloudflare pages project %q: %w", d.Id(), err)) } return nil } @@ -334,6 +331,7 @@ func resourceCloudflarePagesProjectImport(ctx context.Context, d *schema.Resourc tflog.Info(ctx, fmt.Sprintf("Found project: %s", project.Name)) + d.SetId(project.Name) d.Set("name", project.Name) d.Set("account_id", accountID) From f9bf42bdaa082ef265108717510cdb6c3403d1ac Mon Sep 17 00:00:00 2001 From: Jacob White Date: Tue, 13 Sep 2022 19:30:12 -0400 Subject: [PATCH 08/11] Split preview and production deployment configs --- ..._resource_cloudflare_pages_project_test.go | 4 +- .../resource_cloudflare_pages_project.go | 40 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go index aeaa8481b2..af7d87376b 100644 --- a/internal/provider/import_resource_cloudflare_pages_project_test.go +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -18,8 +18,8 @@ func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoNam build_command = "npm run build" destination_dir = "build" root_dir = "/" - web_analytics_tag = "" - web_analytics_token = "" + web_analytics_tag = "cee1c73f6e4743d0b5e6bb1a0bcaabcc" + web_analytics_token = "021e1057c18547eca7b79f2516f06o7x" } source { type = "github" diff --git a/internal/provider/resource_cloudflare_pages_project.go b/internal/provider/resource_cloudflare_pages_project.go index 5b3e1b636a..a40fdc0f6a 100644 --- a/internal/provider/resource_cloudflare_pages_project.go +++ b/internal/provider/resource_cloudflare_pages_project.go @@ -180,6 +180,9 @@ func buildPagesProject(d *schema.ResourceData) cloudflare.PagesProject { if productionBranch, ok := d.GetOk("source.0.config.0.production_branch"); ok { sourceConfig.ProductionBranch = productionBranch.(string) } + if productionBranchEnable, ok := d.GetOk("source.0.config.0.production_deployment_enabled"); ok { + sourceConfig.ProductionDeploymentsEnabled = productionBranchEnable.(bool) + } if previewBranchIncludes, ok := d.GetOk("source.0.config.0.preview_branch_includes"); ok { for _, item := range previewBranchIncludes.([]interface{}) { sourceConfig.PreviewBranchIncludes = append(sourceConfig.PreviewBranchIncludes, item.(string)) @@ -230,14 +233,15 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD "type": project.Source.Type, "config": []map[string]interface{}{ { - "owner": project.Source.Config.Owner, - "repo_name": project.Source.Config.RepoName, - "production_branch": project.Source.Config.ProductionBranch, - "pr_comments_enabled": project.Source.Config.PRCommentsEnabled, - "deployments_enabled": project.Source.Config.DeploymentsEnabled, - "preview_branch_includes": project.Source.Config.PreviewBranchIncludes, - "preview_branch_excludes": project.Source.Config.PreviewBranchExcludes, - "preview_deployment_setting": project.Source.Config.PreviewDeploymentSetting, + "owner": project.Source.Config.Owner, + "repo_name": project.Source.Config.RepoName, + "production_branch": project.Source.Config.ProductionBranch, + "pr_comments_enabled": project.Source.Config.PRCommentsEnabled, + "deployments_enabled": project.Source.Config.DeploymentsEnabled, + "production_deployment_enabled": project.Source.Config.ProductionDeploymentsEnabled, + "preview_branch_includes": project.Source.Config.PreviewBranchIncludes, + "preview_branch_excludes": project.Source.Config.PreviewBranchExcludes, + "preview_deployment_setting": project.Source.Config.PreviewDeploymentSetting, }, }, }, @@ -260,12 +264,20 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD emptyDeploymentConfig := cloudflare.PagesProjectDeploymentConfigs{} if !reflect.DeepEqual(project.DeploymentConfigs, emptyDeploymentConfig) { - deploymentConfig := []map[string]interface{}{} - deploymentConfig = append(deploymentConfig, map[string]interface{}{ - "preview": parseDeployementConfig(project.DeploymentConfigs.Preview), - "production": parseDeployementConfig(project.DeploymentConfigs.Production), - }) - d.Set("deployment_configs", deploymentConfig) + deploymentConfigs := []map[string]interface{}{} + deploymentConfig := make(map[string]interface{}) + emptyDeploymentEnviroment := cloudflare.PagesProjectDeploymentConfigEnvironment{} + if !reflect.DeepEqual(project.DeploymentConfigs.Preview, emptyDeploymentEnviroment) { + fmt.Println("Preview Deployment Enviroment Detected") + deploymentConfig["preview"] = parseDeployementConfig(project.DeploymentConfigs.Preview) + } + + if !reflect.DeepEqual(project.DeploymentConfigs.Production, emptyDeploymentEnviroment) { + fmt.Println("Production Deployment Enviroment Detected") + deploymentConfig["production"] = parseDeployementConfig(project.DeploymentConfigs.Production) + } + deploymentConfigs = append(deploymentConfigs, deploymentConfig) + d.Set("deployment_configs", deploymentConfigs) } return nil From 17ba29f14ad841d0c46756b5b4827d0cd7f4c8df Mon Sep 17 00:00:00 2001 From: Jacob White Date: Tue, 13 Sep 2022 19:35:42 -0400 Subject: [PATCH 09/11] Remove debugging --- internal/provider/resource_cloudflare_pages_project.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/provider/resource_cloudflare_pages_project.go b/internal/provider/resource_cloudflare_pages_project.go index a40fdc0f6a..8fba2035f9 100644 --- a/internal/provider/resource_cloudflare_pages_project.go +++ b/internal/provider/resource_cloudflare_pages_project.go @@ -268,12 +268,10 @@ func resourceCloudflarePagesProjectRead(ctx context.Context, d *schema.ResourceD deploymentConfig := make(map[string]interface{}) emptyDeploymentEnviroment := cloudflare.PagesProjectDeploymentConfigEnvironment{} if !reflect.DeepEqual(project.DeploymentConfigs.Preview, emptyDeploymentEnviroment) { - fmt.Println("Preview Deployment Enviroment Detected") deploymentConfig["preview"] = parseDeployementConfig(project.DeploymentConfigs.Preview) } if !reflect.DeepEqual(project.DeploymentConfigs.Production, emptyDeploymentEnviroment) { - fmt.Println("Production Deployment Enviroment Detected") deploymentConfig["production"] = parseDeployementConfig(project.DeploymentConfigs.Production) } deploymentConfigs = append(deploymentConfigs, deploymentConfig) From 4a8f21fd146af080bb253ec3d5c8cfc205541e1c Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 21 Sep 2022 08:36:23 +1000 Subject: [PATCH 10/11] tidy up example --- docs/resources/pages_project.md | 1 - examples/resources/cloudflare_pages_project/import.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/resources/pages_project.md b/docs/resources/pages_project.md index 89a769b257..d47aaa4446 100644 --- a/docs/resources/pages_project.md +++ b/docs/resources/pages_project.md @@ -207,6 +207,5 @@ Optional: Import is supported using the following syntax: ```shell -# Use account ID, and project name. $ terraform import cloudflare_pages_project.example / ``` diff --git a/examples/resources/cloudflare_pages_project/import.sh b/examples/resources/cloudflare_pages_project/import.sh index e42d04ae52..36bf9dddcf 100644 --- a/examples/resources/cloudflare_pages_project/import.sh +++ b/examples/resources/cloudflare_pages_project/import.sh @@ -1,2 +1 @@ -# Use account ID, and project name. $ terraform import cloudflare_pages_project.example / From 0a71f366dfa580c4400c6ed23dbb7052a8c009cf Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 21 Sep 2022 08:39:33 +1000 Subject: [PATCH 11/11] skip for default account --- .../import_resource_cloudflare_pages_project_test.go | 2 ++ internal/provider/provider_test.go | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/internal/provider/import_resource_cloudflare_pages_project_test.go b/internal/provider/import_resource_cloudflare_pages_project_test.go index af7d87376b..a77d8d2b8a 100644 --- a/internal/provider/import_resource_cloudflare_pages_project_test.go +++ b/internal/provider/import_resource_cloudflare_pages_project_test.go @@ -86,6 +86,8 @@ func testPagesProjectFull(resourceID, accountID, projectName, repoOwner, repoNam } func TestAccCloudflarePagesProject_Import(t *testing.T) { + skipPagesProjectForNonConfiguredDefaultAccount(t) + rnd := generateRandomResourceName() name := fmt.Sprintf("cloudflare_pages_project.%s", rnd) accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 481accf155..034015f0e6 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -201,3 +201,13 @@ func skipV1WAFTestForNonConfiguredDefaultZone(t *testing.T) { t.Skipf("Skipping acceptance test as %s is using WAF v2 and cannot assert v1 resource configurations", testAccCloudflareZoneID) } } + +// skipPagesProjectForNonConfiguredDefaultAccount ignores the pages project tests +// due to not having a dedicated GitHub account setup in Cloudflare for the +// default account. This will allow those who intentionally want to run the test +// to do so while keeping CI sane. +func skipPagesProjectForNonConfiguredDefaultAccount(t *testing.T) { + if os.Getenv("CLOUDFLARE_ACCOUNT_ID") == testAccCloudflareAccountID { + t.Skipf("Skipping acceptance test as %s is using pages project that isn't setup for CI", testAccCloudflareAccountID) + } +}