diff --git a/google/provider.go b/google/provider.go index 8deade14..3dcb14f7 100644 --- a/google/provider.go +++ b/google/provider.go @@ -117,6 +117,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { return mergeResourceMaps( GeneratedAppengineResourcesMap, GeneratedComputeResourcesMap, + GeneratedCloudbuildResourcesMap, GeneratedDnsResourcesMap, GeneratedRedisResourcesMap, GeneratedResourceManagerResourcesMap, @@ -132,7 +133,6 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_billing_account_iam_binding": ResourceIamBindingWithImport(IamBillingAccountSchema, NewBillingAccountIamUpdater, BillingAccountIdParseFunc), "google_billing_account_iam_member": ResourceIamMemberWithImport(IamBillingAccountSchema, NewBillingAccountIamUpdater, BillingAccountIdParseFunc), "google_billing_account_iam_policy": ResourceIamPolicyWithImport(IamBillingAccountSchema, NewBillingAccountIamUpdater, BillingAccountIdParseFunc), - "google_cloudbuild_trigger": resourceCloudBuildTrigger(), "google_cloudfunctions_function": resourceCloudFunctionsFunction(), "google_cloudiot_registry": resourceCloudIoTRegistry(), "google_composer_environment": resourceComposerEnvironment(), diff --git a/google/provider_cloudbuild_gen.go b/google/provider_cloudbuild_gen.go new file mode 100644 index 00000000..d9ea1451 --- /dev/null +++ b/google/provider_cloudbuild_gen.go @@ -0,0 +1,21 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import "github.com/hashicorp/terraform/helper/schema" + +var GeneratedCloudbuildResourcesMap = map[string]*schema.Resource{ + "google_cloudbuild_trigger": resourceCloudbuildTrigger(), +} diff --git a/google/resource_cloudbuild_build_trigger.go b/google/resource_cloudbuild_build_trigger.go deleted file mode 100644 index 3af669fc..00000000 --- a/google/resource_cloudbuild_build_trigger.go +++ /dev/null @@ -1,386 +0,0 @@ -// Package google - implement CRUD operations for Container Registry Build Triggers -// https://cloud.google.com/container-builder/docs/api/reference/rest/v1/projects.triggers#BuildTrigger -package google - -import ( - "encoding/json" - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/cloudbuild/v1" -) - -func resourceCloudBuildTrigger() *schema.Resource { - return &schema.Resource{ - Create: resourceCloudbuildBuildTriggerCreate, - Read: resourceCloudbuildBuildTriggerRead, - Update: resourceCloudbuildBuildTriggerUpdate, - Delete: resourceCloudbuildBuildTriggerDelete, - Importer: &schema.ResourceImporter{ - State: resourceCloudBuildTriggerImportState, - }, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(5 * time.Minute), - Delete: schema.DefaultTimeout(3 * time.Minute), - }, - - SchemaVersion: 1, - - Schema: map[string]*schema.Schema{ - "project": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - "filename": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"build"}, - }, - "build": { - Type: schema.TypeList, - Description: "Contents of the build template.", - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "images": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "step": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Optional: true, - }, - "args": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "tags": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - "description": { - Type: schema.TypeString, - Optional: true, - }, - "substitutions": { - Optional: true, - Type: schema.TypeMap, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "included_files": { - Optional: true, - Type: schema.TypeList, - MaxItems: 50, - ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "ignored_files": { - Optional: true, - Type: schema.TypeList, - MaxItems: 50, - ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "trigger_template": { - Optional: true, - Type: schema.TypeList, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "branch_name": { - Type: schema.TypeString, - Optional: true, - }, - "commit_sha": { - Type: schema.TypeString, - Optional: true, - }, - "dir": { - Type: schema.TypeString, - Optional: true, - }, - "project": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "repo_name": { - Type: schema.TypeString, - Optional: true, - }, - "tag_name": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "trigger_id": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceCloudbuildBuildTriggerCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - buildTrigger, err := expandCloudbuildBuildTrigger(d, meta) - if err != nil { - return err - } - - buildTrigger.IgnoredFiles = expandStringSlice(d, "ignored_files") - buildTrigger.IncludedFiles = expandStringSlice(d, "included_files") - - tstr, err := json.Marshal(buildTrigger) - if err != nil { - return err - } - log.Printf("[INFO] build trigger request: %s", string(tstr)) - trigger, err := config.clientBuild.Projects.Triggers.Create(project, buildTrigger).Do() - if err != nil { - return fmt.Errorf("Error creating build trigger: %s", err) - } - - d.SetId(trigger.Id) - - return resourceCloudbuildBuildTriggerRead(d, meta) -} - -func resourceCloudbuildBuildTriggerRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - ID := d.Id() - buildTrigger, err := config.clientBuild.Projects.Triggers.Get(project, ID).Do() - if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Cloudbuild Trigger %q", ID)) - } - - d.Set("description", buildTrigger.Description) - d.Set("substitutions", buildTrigger.Substitutions) - d.Set("ignored_files", buildTrigger.IgnoredFiles) - d.Set("included_files", buildTrigger.IncludedFiles) - d.Set("trigger_id", buildTrigger.Id) - - if buildTrigger.TriggerTemplate != nil { - d.Set("trigger_template", flattenCloudbuildBuildTriggerTemplate(d, config, buildTrigger.TriggerTemplate)) - } - - if buildTrigger.Filename != "" { - d.Set("filename", buildTrigger.Filename) - } else if buildTrigger.Build != nil { - d.Set("build", flattenCloudbuildBuildTriggerBuild(d, config, buildTrigger.Build)) - } - - return nil -} - -func resourceCloudbuildBuildTriggerUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - buildTrigger, err := expandCloudbuildBuildTrigger(d, meta) - if err != nil { - return err - } - buildTrigger.Id = d.Get("trigger_id").(string) - - id := d.Id() - - log.Printf("[INFO] Updating Cloud Build Trigger: %s", id) - - if _, err = config.clientBuild.Projects.Triggers.Patch(project, id, buildTrigger).Do(); err != nil { - return err - } - - return resourceCloudbuildBuildTriggerRead(d, meta) -} - -func expandCloudbuildBuildTrigger(d *schema.ResourceData, meta interface{}) (*cloudbuild.BuildTrigger, error) { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return nil, err - } - - t := &cloudbuild.BuildTrigger{} - - if v, ok := d.GetOk("description"); ok { - t.Description = v.(string) - } - - if v, ok := d.GetOk("filename"); ok { - t.Filename = v.(string) - } else { - t.Build = expandCloudbuildBuildTriggerBuild(d) - } - - t.Substitutions = expandStringMap(d, "substitutions") - t.TriggerTemplate = expandCloudbuildBuildTriggerTemplate(d, project) - - return t, nil -} - -func expandCloudbuildBuildTriggerTemplate(d *schema.ResourceData, project string) *cloudbuild.RepoSource { - if d.Get("trigger_template.#").(int) == 0 { - return nil - } - tmpl := &cloudbuild.RepoSource{} - if v, ok := d.GetOk("trigger_template.0.project"); ok { - tmpl.ProjectId = v.(string) - } else { - tmpl.ProjectId = project - } - if v, ok := d.GetOk("trigger_template.0.branch_name"); ok { - tmpl.BranchName = v.(string) - } - if v, ok := d.GetOk("trigger_template.0.commit_sha"); ok { - tmpl.CommitSha = v.(string) - } - if v, ok := d.GetOk("trigger_template.0.dir"); ok { - tmpl.Dir = v.(string) - } - if v, ok := d.GetOk("trigger_template.0.repo_name"); ok { - tmpl.RepoName = v.(string) - } - if v, ok := d.GetOk("trigger_template.0.tag_name"); ok { - tmpl.TagName = v.(string) - } - return tmpl -} - -func flattenCloudbuildBuildTriggerTemplate(d *schema.ResourceData, config *Config, t *cloudbuild.RepoSource) []map[string]interface{} { - flattened := make([]map[string]interface{}, 1) - - flattened[0] = map[string]interface{}{ - "branch_name": t.BranchName, - "commit_sha": t.CommitSha, - "dir": t.Dir, - "project": t.ProjectId, - "repo_name": t.RepoName, - "tag_name": t.TagName, - } - - return flattened -} - -func expandCloudbuildBuildTriggerBuild(d *schema.ResourceData) *cloudbuild.Build { - if d.Get("build.#").(int) == 0 { - return nil - } - - build := &cloudbuild.Build{} - if v, ok := d.GetOk("build.0.images"); ok { - build.Images = convertStringArr(v.([]interface{})) - } - if v, ok := d.GetOk("build.0.tags"); ok { - build.Tags = convertStringArr(v.([]interface{})) - } - stepCount := d.Get("build.0.step.#").(int) - build.Steps = make([]*cloudbuild.BuildStep, 0, stepCount) - for s := 0; s < stepCount; s++ { - step := &cloudbuild.BuildStep{ - Name: d.Get(fmt.Sprintf("build.0.step.%d.name", s)).(string), - } - if v, ok := d.GetOk(fmt.Sprintf("build.0.step.%d.args", s)); ok { - step.Args = strings.Split(v.(string), " ") - } - build.Steps = append(build.Steps, step) - } - return build -} - -func flattenCloudbuildBuildTriggerBuild(d *schema.ResourceData, config *Config, b *cloudbuild.Build) []map[string]interface{} { - flattened := make([]map[string]interface{}, 1) - - flattened[0] = map[string]interface{}{} - - if b.Images != nil { - flattened[0]["images"] = convertStringArrToInterface(b.Images) - } - if b.Tags != nil { - flattened[0]["tags"] = convertStringArrToInterface(b.Tags) - } - if b.Steps != nil { - steps := make([]map[string]interface{}, len(b.Steps)) - for i, step := range b.Steps { - steps[i] = map[string]interface{}{} - steps[i]["name"] = step.Name - steps[i]["args"] = strings.Join(step.Args, " ") - } - flattened[0]["step"] = steps - } - - return flattened -} - -func resourceCloudbuildBuildTriggerDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - // Delete the build trigger - log.Printf("[DEBUG] build trigger delete request") - _, err = config.clientBuild.Projects.Triggers.Delete( - project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting build trigger: %s", err) - } - - d.SetId("") - return nil -} - -func resourceCloudBuildTriggerImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), "/") - - if len(parts) == 1 { - return []*schema.ResourceData{d}, nil - } else if len(parts) == 2 { - d.Set("project", parts[0]) - d.SetId(parts[1]) - return []*schema.ResourceData{d}, nil - } else { - return nil, fmt.Errorf("Invalid import id %q. Expecting {trigger_name} or {project}/{trigger_name}", d.Id()) - } -} diff --git a/google/resource_cloudbuild_build_trigger_test.go b/google/resource_cloudbuild_build_trigger_test.go index 67b9201a..0cbda174 100644 --- a/google/resource_cloudbuild_build_trigger_test.go +++ b/google/resource_cloudbuild_build_trigger_test.go @@ -4,50 +4,32 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" - cloudbuild "google.golang.org/api/cloudbuild/v1" ) func TestAccCloudBuildTrigger_basic(t *testing.T) { t.Parallel() - projectID := "terraform-" + acctest.RandString(10) - projectOrg := getTestOrgFromEnv(t) - projectBillingAccount := getTestBillingAccountFromEnv(t) - resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckGoogleCloudBuildTriggerVersionsDestroyed, + CheckDestroy: testAccCheckCloudbuildTriggerDestroy, Steps: []resource.TestStep{ { - Config: testGoogleCloudBuildTrigger_basic(projectID, projectOrg, projectBillingAccount), - Check: resource.ComposeTestCheckFunc( - testAccCheckGoogleCloudBuildTriggerExists("google_cloudbuild_trigger.build_trigger"), - ), + Config: testGoogleCloudBuildTrigger_basic(), }, { - ResourceName: "google_cloudbuild_trigger.build_trigger", - ImportState: true, - ImportStateVerify: true, - ImportStateIdPrefix: fmt.Sprintf("%s/", projectID), + ResourceName: "google_cloudbuild_trigger.build_trigger", + ImportState: true, + ImportStateVerify: true, }, { - Config: testGoogleCloudBuildTrigger_updated(projectID, projectOrg, projectBillingAccount), + Config: testGoogleCloudBuildTrigger_updated(), }, { - ResourceName: "google_cloudbuild_trigger.build_trigger", - ImportState: true, - ImportStateVerify: true, - ImportStateIdPrefix: fmt.Sprintf("%s/", projectID), - }, - { - Config: testGoogleCloudBuildTrigger_removed(projectID, projectOrg, projectBillingAccount), - Check: resource.ComposeTestCheckFunc( - testAccCheckGoogleCloudBuildTriggerWasRemovedFromState("google_cloudbuild_trigger.build_trigger"), - ), + ResourceName: "google_cloudbuild_trigger.build_trigger", + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -56,147 +38,30 @@ func TestAccCloudBuildTrigger_basic(t *testing.T) { func TestAccCloudBuildTrigger_filename(t *testing.T) { t.Parallel() - projectID := "terraform-" + acctest.RandString(10) - projectOrg := getTestOrgFromEnv(t) - projectBillingAccount := getTestBillingAccountFromEnv(t) - resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckGoogleCloudBuildTriggerVersionsDestroyed, + CheckDestroy: testAccCheckCloudbuildTriggerDestroy, Steps: []resource.TestStep{ { - Config: testGoogleCloudBuildTrigger_filename(projectID, projectOrg, projectBillingAccount), - Check: resource.ComposeTestCheckFunc( - testAccCheckGoogleCloudFilenameConfig("google_cloudbuild_trigger.filename_build_trigger"), - ), + Config: testGoogleCloudBuildTrigger_filename(), }, { - Config: testGoogleCloudBuildTrigger_removed(projectID, projectOrg, projectBillingAccount), - Check: resource.ComposeTestCheckFunc( - testAccCheckGoogleCloudBuildTriggerWasRemovedFromState("google_cloudbuild_trigger.filename_build_trigger"), - ), + ResourceName: "google_cloudbuild_trigger.filename_build_trigger", + ImportState: true, + ImportStateVerify: true, }, }, }) } -func testAccGetBuildTrigger(s *terraform.State, resourceName string) (*cloudbuild.BuildTrigger, error) { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return nil, fmt.Errorf("Resource not found: %s", resourceName) - } - - if rs.Primary.ID == "" { - return nil, fmt.Errorf("No ID is set") - } - - config := testAccProvider.Meta().(*Config) - project := rs.Primary.Attributes["project"] - - trigger, err := config.clientBuild.Projects.Triggers.Get(project, rs.Primary.ID).Do() - if err != nil { - return nil, fmt.Errorf("Trigger does not exist") - } - - return trigger, nil -} - -func testAccCheckGoogleCloudBuildTriggerExists(resourceName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _, err := testAccGetBuildTrigger(s, resourceName) - - if err != nil { - return fmt.Errorf("Trigger does not exist") - } - - return nil - } -} - -func testAccCheckGoogleCloudFilenameConfig(resourceName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - trigger, err := testAccGetBuildTrigger(s, resourceName) - - if err != nil { - return fmt.Errorf("Trigger does not exist") - } - - if trigger.Filename != "cloudbuild.yaml" { - return fmt.Errorf("Config filename mismatch: %s", trigger.Filename) - } - - return nil - } -} - -func testAccCheckGoogleCloudBuildTriggerWasRemovedFromState(resourceName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[resourceName] - - if ok { - return fmt.Errorf("Resource was not removed from state: %s", resourceName) - } - - return nil - } -} - -func testAccCheckGoogleCloudBuildTriggerVersionsDestroyed(s *terraform.State) error { - config := testAccProvider.Meta().(*Config) - - for _, rs := range s.RootModule().Resources { - if rs.Type != "google_cloudbuild_trigger" { - continue - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - project := rs.Primary.Attributes["project"] - - _, err := config.clientBuild.Projects.Triggers.Get(project, rs.Primary.ID).Do() - if err == nil { - return fmt.Errorf("Trigger still exists") - } - - } - - return nil -} - -/* - This test runs in its own project, otherwise the test project would start to get filled - with undeletable resources -*/ -func testGoogleCloudBuildTrigger_basic(projectID, projectOrg, projectBillingAccount string) string { +func testGoogleCloudBuildTrigger_basic() string { return fmt.Sprintf(` -resource "google_project" "acceptance" { - name = "%s" - project_id = "%s" - org_id = "%s" - billing_account = "%s" -} - -resource "google_project_services" "acceptance" { - project = "${google_project.acceptance.project_id}" - - services = [ - "cloudbuild.googleapis.com", - "containerregistry.googleapis.com", - "logging.googleapis.com", - "pubsub.googleapis.com", - "storage-api.googleapis.com", - ] -} - resource "google_cloudbuild_trigger" "build_trigger" { - project = "${google_project_services.acceptance.project}" description = "acceptance test build trigger" trigger_template { branch_name = "master" - project = "${google_project_services.acceptance.project}" repo_name = "some-repo" } build { @@ -204,48 +69,27 @@ resource "google_cloudbuild_trigger" "build_trigger" { tags = ["team-a", "service-b"] step { name = "gcr.io/cloud-builders/gsutil" - args = "cp gs://mybucket/remotefile.zip localfile.zip " + args = ["cp", "gs://mybucket/remotefile.zip", "localfile.zip"] } step { name = "gcr.io/cloud-builders/go" - args = "build my_package" + args = ["build", "my_package"] } step { name = "gcr.io/cloud-builders/docker" - args = "build -t gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA -f Dockerfile ." + args = ["build", "-t", "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA", "-f", "Dockerfile", "."] } } } - `, projectID, projectID, projectOrg, projectBillingAccount) + `) } -func testGoogleCloudBuildTrigger_updated(projectID, projectOrg, projectBillingAccount string) string { +func testGoogleCloudBuildTrigger_updated() string { return fmt.Sprintf(` -resource "google_project" "acceptance" { - name = "%s" - project_id = "%s" - org_id = "%s" - billing_account = "%s" -} - -resource "google_project_services" "acceptance" { - project = "${google_project.acceptance.project_id}" - - services = [ - "cloudbuild.googleapis.com", - "containerregistry.googleapis.com", - "logging.googleapis.com", - "pubsub.googleapis.com", - "storage-api.googleapis.com", - ] -} - resource "google_cloudbuild_trigger" "build_trigger" { - project = "${google_project_services.acceptance.project}" description = "acceptance test build trigger updated" trigger_template { branch_name = "master-updated" - project = "${google_project_services.acceptance.project}" repo_name = "some-repo-updated" } build { @@ -253,48 +97,28 @@ resource "google_cloudbuild_trigger" "build_trigger" { tags = ["team-a", "service-b", "updated"] step { name = "gcr.io/cloud-builders/gsutil" - args = "cp gs://mybucket/remotefile.zip localfile-updated.zip " + args = ["cp", "gs://mybucket/remotefile.zip", "localfile-updated.zip"] } step { name = "gcr.io/cloud-builders/go" - args = "build my_package_updated" + args = ["build", "my_package_updated"] } step { name = "gcr.io/cloud-builders/docker" - args = "build -t gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA -f Dockerfile ." + args = ["build", "-t", "gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA", "-f", "Dockerfile", "."] } step { name = "gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA" - args = "test" + args = ["test"] } } } - `, projectID, projectID, projectOrg, projectBillingAccount) + `) } -func testGoogleCloudBuildTrigger_filename(projectID, projectOrg, projectBillingAccount string) string { +func testGoogleCloudBuildTrigger_filename() string { return fmt.Sprintf(` -resource "google_project" "acceptance" { - name = "%s" - project_id = "%s" - org_id = "%s" - billing_account = "%s" -} - -resource "google_project_services" "acceptance" { - project = "${google_project.acceptance.project_id}" - - services = [ - "cloudbuild.googleapis.com", - "containerregistry.googleapis.com", - "logging.googleapis.com", - "pubsub.googleapis.com", - "storage-api.googleapis.com", - ] -} - resource "google_cloudbuild_trigger" "filename_build_trigger" { - project = "${google_project_services.acceptance.project}" description = "acceptance test build trigger" trigger_template { branch_name = "master" @@ -306,28 +130,5 @@ resource "google_cloudbuild_trigger" "filename_build_trigger" { } filename = "cloudbuild.yaml" } - `, projectID, projectID, projectOrg, projectBillingAccount) -} - -func testGoogleCloudBuildTrigger_removed(projectID, projectOrg, projectBillingAccount string) string { - return fmt.Sprintf(` -resource "google_project" "acceptance" { - name = "%s" - project_id = "%s" - org_id = "%s" - billing_account = "%s" -} - -resource "google_project_services" "acceptance" { - project = "${google_project.acceptance.project_id}" - - services = [ - "cloudbuild.googleapis.com", - "containerregistry.googleapis.com", - "logging.googleapis.com", - "pubsub.googleapis.com", - "storage-api.googleapis.com", - ] -} - `, projectID, projectID, projectOrg, projectBillingAccount) + `) } diff --git a/google/resource_cloudbuild_trigger.go b/google/resource_cloudbuild_trigger.go new file mode 100644 index 00000000..bbf8cb8a --- /dev/null +++ b/google/resource_cloudbuild_trigger.go @@ -0,0 +1,730 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceCloudbuildTrigger() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudbuildTriggerCreate, + Read: resourceCloudbuildTriggerRead, + Update: resourceCloudbuildTriggerUpdate, + Delete: resourceCloudbuildTriggerDelete, + + Importer: &schema.ResourceImporter{ + State: resourceCloudbuildTriggerImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + + SchemaVersion: 1, + + Schema: map[string]*schema.Schema{ + "build": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "images": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "step": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "args": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + ConflictsWith: []string{"filename"}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "disabled": { + Type: schema.TypeString, + Optional: true, + }, + "filename": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"build"}, + }, + "ignored_files": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "included_files": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "substitutions": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "trigger_template": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "branch_name": { + Type: schema.TypeString, + Optional: true, + }, + "commit_sha": { + Type: schema.TypeString, + Optional: true, + }, + "dir": { + Type: schema.TypeString, + Optional: true, + }, + "project_id": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "repo_name": { + Type: schema.TypeString, + Optional: true, + Default: "default", + }, + "tag_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "trigger_id": { + Type: schema.TypeString, + Computed: true, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudbuildTriggerCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + descriptionProp, err := expandCloudbuildTriggerDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + disabledProp, err := expandCloudbuildTriggerDisabled(d.Get("disabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("disabled"); !isEmptyValue(reflect.ValueOf(disabledProp)) && (ok || !reflect.DeepEqual(v, disabledProp)) { + obj["disabled"] = disabledProp + } + substitutionsProp, err := expandCloudbuildTriggerSubstitutions(d.Get("substitutions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("substitutions"); !isEmptyValue(reflect.ValueOf(substitutionsProp)) && (ok || !reflect.DeepEqual(v, substitutionsProp)) { + obj["substitutions"] = substitutionsProp + } + filenameProp, err := expandCloudbuildTriggerFilename(d.Get("filename"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("filename"); !isEmptyValue(reflect.ValueOf(filenameProp)) && (ok || !reflect.DeepEqual(v, filenameProp)) { + obj["filename"] = filenameProp + } + ignoredFilesProp, err := expandCloudbuildTriggerIgnoredFiles(d.Get("ignored_files"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("ignored_files"); !isEmptyValue(reflect.ValueOf(ignoredFilesProp)) && (ok || !reflect.DeepEqual(v, ignoredFilesProp)) { + obj["ignoredFiles"] = ignoredFilesProp + } + includedFilesProp, err := expandCloudbuildTriggerIncludedFiles(d.Get("included_files"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("included_files"); !isEmptyValue(reflect.ValueOf(includedFilesProp)) && (ok || !reflect.DeepEqual(v, includedFilesProp)) { + obj["includedFiles"] = includedFilesProp + } + triggerTemplateProp, err := expandCloudbuildTriggerTriggerTemplate(d.Get("trigger_template"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("trigger_template"); !isEmptyValue(reflect.ValueOf(triggerTemplateProp)) && (ok || !reflect.DeepEqual(v, triggerTemplateProp)) { + obj["triggerTemplate"] = triggerTemplateProp + } + buildProp, err := expandCloudbuildTriggerBuild(d.Get("build"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("build"); !isEmptyValue(reflect.ValueOf(buildProp)) && (ok || !reflect.DeepEqual(v, buildProp)) { + obj["build"] = buildProp + } + + url, err := replaceVars(d, config, "https://cloudbuild.googleapis.com/v1/projects/{{project}}/triggers") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Trigger: %#v", obj) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating Trigger: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{project}}/{{trigger_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Trigger %q: %#v", d.Id(), res) + + // `name` is autogenerated from the api so needs to be set post-create + triggerId, ok := res["id"] + if !ok { + return fmt.Errorf("Create response didn't contain id. Create may not have succeeded.") + } + d.Set("trigger_id", triggerId.(string)) + + // Store the ID now. We tried to set it before and it failed because + // trigger_id didn't exist yet. + id, err = replaceVars(d, config, "{{project}}/{{trigger_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return resourceCloudbuildTriggerRead(d, meta) +} + +func resourceCloudbuildTriggerRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://cloudbuild.googleapis.com/v1/projects/{{project}}/triggers/{{trigger_id}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("CloudbuildTrigger %q", d.Id())) + } + + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + + if err := d.Set("trigger_id", flattenCloudbuildTriggerTrigger_id(res["id"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("description", flattenCloudbuildTriggerDescription(res["description"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("disabled", flattenCloudbuildTriggerDisabled(res["disabled"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("create_time", flattenCloudbuildTriggerCreateTime(res["createTime"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("substitutions", flattenCloudbuildTriggerSubstitutions(res["substitutions"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("filename", flattenCloudbuildTriggerFilename(res["filename"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("ignored_files", flattenCloudbuildTriggerIgnoredFiles(res["ignoredFiles"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("included_files", flattenCloudbuildTriggerIncludedFiles(res["includedFiles"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("trigger_template", flattenCloudbuildTriggerTriggerTemplate(res["triggerTemplate"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + if err := d.Set("build", flattenCloudbuildTriggerBuild(res["build"], d)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } + + return nil +} + +func resourceCloudbuildTriggerUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + descriptionProp, err := expandCloudbuildTriggerDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + disabledProp, err := expandCloudbuildTriggerDisabled(d.Get("disabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("disabled"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, disabledProp)) { + obj["disabled"] = disabledProp + } + substitutionsProp, err := expandCloudbuildTriggerSubstitutions(d.Get("substitutions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("substitutions"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, substitutionsProp)) { + obj["substitutions"] = substitutionsProp + } + filenameProp, err := expandCloudbuildTriggerFilename(d.Get("filename"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("filename"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, filenameProp)) { + obj["filename"] = filenameProp + } + triggerTemplateProp, err := expandCloudbuildTriggerTriggerTemplate(d.Get("trigger_template"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("trigger_template"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, triggerTemplateProp)) { + obj["triggerTemplate"] = triggerTemplateProp + } + buildProp, err := expandCloudbuildTriggerBuild(d.Get("build"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("build"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, buildProp)) { + obj["build"] = buildProp + } + + url, err := replaceVars(d, config, "https://cloudbuild.googleapis.com/v1/projects/{{project}}/triggers/{{trigger_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Trigger %q: %#v", d.Id(), obj) + obj["id"] = d.Get("trigger_id") + _, err = sendRequestWithTimeout(config, "PATCH", url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating Trigger %q: %s", d.Id(), err) + } + + return resourceCloudbuildTriggerRead(d, meta) +} + +func resourceCloudbuildTriggerDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://cloudbuild.googleapis.com/v1/projects/{{project}}/triggers/{{trigger_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Trigger %q", d.Id()) + res, err := sendRequestWithTimeout(config, "DELETE", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "Trigger") + } + + log.Printf("[DEBUG] Finished deleting Trigger %q: %#v", d.Id(), res) + return nil +} + +func resourceCloudbuildTriggerImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{"projects/(?P[^/]+)/triggers/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{project}}/{{trigger_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenCloudbuildTriggerTrigger_id(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerDisabled(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerCreateTime(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerSubstitutions(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerFilename(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerIgnoredFiles(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerIncludedFiles(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerTriggerTemplate(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["project_id"] = + flattenCloudbuildTriggerTriggerTemplateProjectId(original["projectId"], d) + transformed["repo_name"] = + flattenCloudbuildTriggerTriggerTemplateRepoName(original["repoName"], d) + transformed["dir"] = + flattenCloudbuildTriggerTriggerTemplateDir(original["dir"], d) + transformed["branch_name"] = + flattenCloudbuildTriggerTriggerTemplateBranchName(original["branchName"], d) + transformed["tag_name"] = + flattenCloudbuildTriggerTriggerTemplateTagName(original["tagName"], d) + transformed["commit_sha"] = + flattenCloudbuildTriggerTriggerTemplateCommitSha(original["commitSha"], d) + return []interface{}{transformed} +} +func flattenCloudbuildTriggerTriggerTemplateProjectId(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerTriggerTemplateRepoName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerTriggerTemplateDir(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerTriggerTemplateBranchName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerTriggerTemplateTagName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerTriggerTemplateCommitSha(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerBuild(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["tags"] = + flattenCloudbuildTriggerBuildTags(original["tags"], d) + transformed["images"] = + flattenCloudbuildTriggerBuildImages(original["images"], d) + transformed["step"] = + flattenCloudbuildTriggerBuildStep(original["steps"], d) + return []interface{}{transformed} +} +func flattenCloudbuildTriggerBuildTags(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerBuildImages(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerBuildStep(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "name": flattenCloudbuildTriggerBuildStepName(original["name"], d), + "args": flattenCloudbuildTriggerBuildStepArgs(original["args"], d), + }) + } + return transformed +} +func flattenCloudbuildTriggerBuildStepName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenCloudbuildTriggerBuildStepArgs(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandCloudbuildTriggerDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerDisabled(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerSubstitutions(v interface{}, d *schema.ResourceData, config *Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} + +func expandCloudbuildTriggerFilename(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerIgnoredFiles(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerIncludedFiles(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerTriggerTemplate(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedProjectId, err := expandCloudbuildTriggerTriggerTemplateProjectId(original["project_id"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProjectId); val.IsValid() && !isEmptyValue(val) { + transformed["projectId"] = transformedProjectId + } + + transformedRepoName, err := expandCloudbuildTriggerTriggerTemplateRepoName(original["repo_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRepoName); val.IsValid() && !isEmptyValue(val) { + transformed["repoName"] = transformedRepoName + } + + transformedDir, err := expandCloudbuildTriggerTriggerTemplateDir(original["dir"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDir); val.IsValid() && !isEmptyValue(val) { + transformed["dir"] = transformedDir + } + + transformedBranchName, err := expandCloudbuildTriggerTriggerTemplateBranchName(original["branch_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedBranchName); val.IsValid() && !isEmptyValue(val) { + transformed["branchName"] = transformedBranchName + } + + transformedTagName, err := expandCloudbuildTriggerTriggerTemplateTagName(original["tag_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTagName); val.IsValid() && !isEmptyValue(val) { + transformed["tagName"] = transformedTagName + } + + transformedCommitSha, err := expandCloudbuildTriggerTriggerTemplateCommitSha(original["commit_sha"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCommitSha); val.IsValid() && !isEmptyValue(val) { + transformed["commitSha"] = transformedCommitSha + } + + return transformed, nil +} + +func expandCloudbuildTriggerTriggerTemplateProjectId(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerTriggerTemplateRepoName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerTriggerTemplateDir(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerTriggerTemplateBranchName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerTriggerTemplateTagName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerTriggerTemplateCommitSha(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerBuild(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedTags, err := expandCloudbuildTriggerBuildTags(original["tags"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTags); val.IsValid() && !isEmptyValue(val) { + transformed["tags"] = transformedTags + } + + transformedImages, err := expandCloudbuildTriggerBuildImages(original["images"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedImages); val.IsValid() && !isEmptyValue(val) { + transformed["images"] = transformedImages + } + + transformedStep, err := expandCloudbuildTriggerBuildStep(original["step"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStep); val.IsValid() && !isEmptyValue(val) { + transformed["steps"] = transformedStep + } + + return transformed, nil +} + +func expandCloudbuildTriggerBuildTags(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerBuildImages(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerBuildStep(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandCloudbuildTriggerBuildStepName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) { + transformed["name"] = transformedName + } + + transformedArgs, err := expandCloudbuildTriggerBuildStepArgs(original["args"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedArgs); val.IsValid() && !isEmptyValue(val) { + transformed["args"] = transformedArgs + } + + req = append(req, transformed) + } + return req, nil +} + +func expandCloudbuildTriggerBuildStepName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudbuildTriggerBuildStepArgs(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_cloudbuild_trigger_generated_test.go b/google/resource_cloudbuild_trigger_generated_test.go new file mode 100644 index 00000000..e6207b37 --- /dev/null +++ b/google/resource_cloudbuild_trigger_generated_test.go @@ -0,0 +1,92 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccCloudbuildTrigger_cloudbuildTriggerFilenameExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudbuildTriggerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCloudbuildTrigger_cloudbuildTriggerFilenameExample(context), + }, + { + ResourceName: "google_cloudbuild_trigger.filename-trigger", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCloudbuildTrigger_cloudbuildTriggerFilenameExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloudbuild_trigger" "filename-trigger" { + trigger_template { + branch_name = "master" + repo_name = "my-repo" + } + + substitutions = { + _FOO = "bar" + _BAZ = "qux" + } + + filename = "cloudbuild.yaml" +} +`, context) +} + +func testAccCheckCloudbuildTriggerDestroy(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_cloudbuild_trigger" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := testAccProvider.Meta().(*Config) + + url, err := replaceVarsForTest(rs, "https://cloudbuild.googleapis.com/v1/projects/{{project}}/triggers/{{trigger_id}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", url, nil) + if err == nil { + return fmt.Errorf("CloudbuildTrigger still exists at %s", url) + } + } + + return nil +} diff --git a/google/utils.go b/google/utils.go index 3c1bde65..305ee7ef 100644 --- a/google/utils.go +++ b/google/utils.go @@ -212,19 +212,6 @@ func expandEnvironmentVariables(d *schema.ResourceData) map[string]string { return expandStringMap(d, "environment_variables") } -// expandStringSlice pulls the value of key out of schema.ResourceData as a []string -func expandStringSlice(d *schema.ResourceData, key string) []string { - var strings []string - - if interfaceStrings, ok := d.GetOk(key); ok { - for _, str := range interfaceStrings.([]interface{}) { - strings = append(strings, str.(string)) - } - } - - return strings -} - // expandStringMap pulls the value of key out of a schema.ResourceData as a map[string]string. func expandStringMap(d *schema.ResourceData, key string) map[string]string { v, ok := d.GetOk(key) diff --git a/website/docs/r/cloudbuild_trigger.html.markdown b/website/docs/r/cloudbuild_trigger.html.markdown index d5694d5b..6827812c 100644 --- a/website/docs/r/cloudbuild_trigger.html.markdown +++ b/website/docs/r/cloudbuild_trigger.html.markdown @@ -1,157 +1,223 @@ --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_cloudbuild_trigger" sidebar_current: "docs-google-cloudbuild-trigger" description: |- - Creates a new build trigger within GCR. + Configuration for an automated build in response to source repository changes. --- # google\_cloudbuild\_trigger -Creates a new build trigger within GCR. For more information, see -[the official documentation](https://cloud.google.com/container-builder/docs/running-builds/automate-builds) -and -[API](https://godoc.org/google.golang.org/api/cloudbuild/v1#BuildTrigger). +Configuration for an automated build in response to source repository changes. + + +To get more information about Trigger, see: + +* [API documentation](https://cloud.google.com/cloud-build/docs/api/reference/rest/) +* How-to Guides + * [Automating builds using build triggers](https://cloud.google.com/cloud-build/docs/running-builds/automate-builds) + + +## Example Usage - Cloudbuild Trigger Filename -## Example Usage ```hcl -resource "google_cloudbuild_trigger" "build_trigger" { - project = "my-project" +resource "google_cloudbuild_trigger" "filename-trigger" { trigger_template { branch_name = "master" - project = "my-project" - repo_name = "some-repo" + repo_name = "my-repo" } - build { - images = ["gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA"] - step { - name = "gcr.io/cloud-builders/docker" - args = "build -t gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA -f Dockerfile ." - } - } -} -``` -OR - -```hcl -resource "google_cloudbuild_trigger" "build_trigger" { - project = "my-project" - trigger_template { - branch_name = "master" - project = "my-project" - repo_name = "some-repo" + substitutions = { + _FOO = "bar" + _BAZ = "qux" } + filename = "cloudbuild.yaml" } ``` - ## Argument Reference -(Argument descriptions sourced from https://godoc.org/google.golang.org/api/cloudbuild/v1#BuildTrigger) - The following arguments are supported: -* `build` - (Optional) A build resource in the Container Builder API. -Structure is documented below. At a high -level, a `build` describes where to find source code, how to build it (for -example, the builder image to run on the source), and where to store -the built artifacts. Fields can include the following variables, which -will be expanded when the build is created: - * `$PROJECT_ID`: the project ID of the build. - * `$BUILD_ID`: the autogenerated ID of the build. - * `$REPO_NAME`: the source repository name specified by RepoSource. - * `$BRANCH_NAME`: the branch name specified by RepoSource. - * `$TAG_NAME`: the tag name specified by RepoSource. - * `$REVISION_ID` or `$COMMIT_SHA`: the commit SHA specified by RepoSource - or resolved from the specified branch or tag. - * `$SHORT_SHA`: first 7 characters of `$REVISION_ID` or `$COMMIT_SHA`. -* `description` - (Optional) A brief description of this resource. -* `ignored_files` - (Optional) `ignored_files` and `included_files` are file glob matches using http://godoc/pkg/path/filepath#Match extended with support for "\*\*". If `ignored_files` and changed files are both empty, then they are not used to determine whether or not to trigger a build. If `ignored_files` is not empty, then we ignore any files that match any of the ignored_file globs. If the change has no files that are outside of the `ignored_files` globs, then - we do not trigger a build. +- - - -* `included_files` - (Optional) If any of the files altered in the commit pass the `ignored_files` filter and `included_files` is empty, then as far as this filter is concerned, we should trigger the build. If any of the files altered in the commit pass the `ignored_files` filter and `included_files` is not empty, then we make sure that at least one of those files matches a `included_files` glob. If not, then we do not trigger a build. -* `filename` - (Optional) Specify the path to a Cloud Build configuration file -in the Git repo. This is mutually exclusive with `build`. This is typically -`cloudbuild.yaml` however it can be specified by the user. +* `description` - + (Optional) + Human-readable description of the trigger. -* `project` - (Optional) The ID of the project that the trigger will be created in. -Defaults to the provider project configuration. +* `disabled` - + (Optional) + Whether the trigger is disabled or not. If true, the trigger will never result in a build. -* `substitutions`: (Optional) User-defined substitutions. -User-defined substitutions must conform to the following rules: - * Substitutions must begin with an underscore (`_`) and use only - uppercase-letters and numbers (respecting the regular expression - `_[A-Z0-9_]+`). This prevents conflicts with built-in substitutions. - * Unmatched keys in the template will cause an error (for example, if a build - request includes `$_FOO` and the substitutions map doesn’t define `_FOO`). - * Unmatched keys in the parameters list will result in an error (for example, - if a substitutions map defines `_FOO` but the build request doesn't include `$_FOO`). - * To include a literal `$_VARIABLE` in the template, you must escape with `$$`. - * You can explicitly denote variable expansion using the `${_VAR}` syntax. This prevents - ambiguity in cases like `${_FOO}BAR`, where `$_FOO` is a variable. - * The number of parameters is limited to 100 parameters. - * The length of a parameter key and the length of a parameter value - are limited to 100 characters. +* `substitutions` - + (Optional) + Substitutions data for Build resource. -* `trigger_template` - (Optional) Location of the source in a Google -Cloud Source Repository. Structure is documented below. +* `filename` - + (Optional) + Path, from the source root, to a file whose contents is used for the template. ---- +* `ignored_files` - + (Optional) + ignoredFiles and includedFiles are file glob matches using http://godoc/pkg/path/filepath#Match + extended with support for "**". + If ignoredFiles and changed files are both empty, then they are not + used to determine whether or not to trigger a build. + If ignoredFiles is not empty, then we ignore any files that match any + of the ignored_file globs. If the change has no files that are outside + of the ignoredFiles globs, then we do not trigger a build. -The `build` block supports: +* `included_files` - + (Optional) + ignoredFiles and includedFiles are file glob matches using http://godoc/pkg/path/filepath#Match + extended with support for "**". + If any of the files altered in the commit pass the ignoredFiles filter + and includedFiles is empty, then as far as this filter is concerned, we + should trigger the build. + If any of the files altered in the commit pass the ignoredFiles filter + and includedFiles is not empty, then we make sure that at least one of + those files matches a includedFiles glob. If not, then we do not trigger + a build. -* `images` - (Optional) A list of images to be pushed upon the successful -completion of all build steps. +* `trigger_template` - + (Optional) + Template describing the types of source changes to trigger a build. + Branch and tag names in trigger templates are interpreted as regular + expressions. Any branch or tag change that matches that regular + expression will trigger a build. Structure is documented below. -* `step` - (Optional) The operations to be performed on the workspace. -Structure is documented below. +* `build` - + (Optional) + Contents of the build template. Structure is documented below. +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `tags` - (Optional) Tags for annotation of a build. **These are not docker tags** - ---- - -The `step` block supports: - -* `name` - (Optional) The name of the container image that will run this -particular build step. If the image is available in the host's Docker -daemon's cache, it will be run directly. If not, the host will attempt to -pull the image first, using the builder service account's credentials if -necessary. The Docker daemon's cache will already have the latest versions -of all of the officially supported build steps -(https://github.com/GoogleCloudPlatform/cloud-builders). -The Docker daemon will also have cached many of the layers for some popular -images, like "ubuntu", "debian", but they will be refreshed at the time you -attempt to use them. If you built an image in a previous build step, it will -be stored in the host's Docker daemon's cache and is available to use as -the name for a later build step. - -* `args` - (Optional) A list of arguments that will be presented to the step -when it is started. If the image used to run the step's container has an -entrypoint, the `args` are used as arguments to that entrypoint. If the image -does not define an entrypoint, the first element in args is used as the -entrypoint, and the remainder will be used as arguments. - ---- The `trigger_template` block supports: -* `branch_name` - (Optional) Name of the branch to build. +* `project_id` - + (Optional) + ID of the project that owns the Cloud Source Repository. If + omitted, the project ID requesting the build is assumed. -* `commit_sha` - (Optional) Explicit commit SHA to build. +* `repo_name` - + (Optional) + Name of the Cloud Source Repository. If omitted, the name "default" is assumed. -* `dir` - (Optional) Directory, relative to the source root, in which to run -the build. This must be a relative path. If a step's `dir` is specified and -is an absolute path, this value is ignored for that step's execution. +* `dir` - + (Optional) + Directory, relative to the source root, in which to run the build. + This must be a relative path. If a step's dir is specified and + is an absolute path, this value is ignored for that step's + execution. -* `project` - (Optional) ID of the project that owns the Cloud Source Repository. +* `branch_name` - + (Optional) + Name of the branch to build. -* `repo_name` - (Optional) Name of the Cloud Source Repository. +* `tag_name` - + (Optional) + Name of the tag to build. -* `tag_name` - (Optional) Name of the tag to build. +* `commit_sha` - + (Optional) + Explicit commit SHA to build. +The `build` block supports: + +* `tags` - + (Optional) + Tags for annotation of a Build. These are not docker tags. + +* `images` - + (Optional) + A list of images to be pushed upon the successful completion of all build steps. + The images are pushed using the builder service account's credentials. + The digests of the pushed images will be stored in the Build resource's results field. + If any of the images fail to be pushed, the build status is marked FAILURE. + +* `step` - + (Optional) + The operations to be performed on the workspace. Structure is documented below. + + +The `step` block supports: + +* `name` - + (Optional) + The name of the container image that will run this particular build step. + If the image is available in the host's Docker daemon's cache, it will be + run directly. If not, the host will attempt to pull the image first, using + the builder service account's credentials if necessary. + The Docker daemon's cache will already have the latest versions of all of + the officially supported build steps (https://github.com/GoogleCloudPlatform/cloud-builders). + The Docker daemon will also have cached many of the layers for some popular + images, like "ubuntu", "debian", but they will be refreshed at the time + you attempt to use them. + If you built an image in a previous build step, it will be stored in the + host's Docker daemon's cache and is available to use as the name for a + later build step. + +* `args` - + (Optional) + A list of arguments that will be presented to the step when it is started. + If the image used to run the step's container has an entrypoint, the args + are used as arguments to that entrypoint. If the image does not define an + entrypoint, the first element in args is used as the entrypoint, and the + remainder will be used as arguments. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + + +* `trigger_id` - + The unique identifier for the trigger. + +* `create_time` - + Time when the trigger was created. + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +Trigger can be imported using any of these accepted formats: + +``` +$ terraform import google_cloudbuild_trigger.default projects/{{project}}/triggers/{{trigger_id}} +$ terraform import google_cloudbuild_trigger.default {{project}}/{{trigger_id}} +$ terraform import google_cloudbuild_trigger.default {{trigger_id}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource.