diff --git a/build/terraform b/build/terraform index 48a2cf8a2752..66d08dac5833 160000 --- a/build/terraform +++ b/build/terraform @@ -1 +1 @@ -Subproject commit 48a2cf8a27521c67ad14f63f83b3d299166844f2 +Subproject commit 66d08dac5833dd501cb82cdbdb5593dbc064e444 diff --git a/build/terraform-beta b/build/terraform-beta index cc333ab87688..2dbae9960753 160000 --- a/build/terraform-beta +++ b/build/terraform-beta @@ -1 +1 @@ -Subproject commit cc333ab876880b1609e556911cf9171a91ce002c +Subproject commit 2dbae9960753eb6a782db4a1be1c897a78dabd8b diff --git a/products/cloudbuild/api.yaml b/products/cloudbuild/api.yaml new file mode 100644 index 000000000000..09c51050f666 --- /dev/null +++ b/products/cloudbuild/api.yaml @@ -0,0 +1,184 @@ +# Copyright 2018 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Api::Product +name: Cloud Build +prefix: gcloudbuild +versions: + - !ruby/object:Api::Product::Version + name: ga + base_url: https://cloudbuild.googleapis.com/v1/ +scopes: + - https://www.googleapis.com/auth/cloud-platform +objects: + - !ruby/object:Api::Resource + name: 'Trigger' + base_url: projects/{{project}}/triggers + self_link: projects/{{project}}/triggers/{{id}} + update_verb: :PATCH + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Automating builds using build triggers': 'https://cloud.google.com/cloud-build/docs/running-builds/automate-builds' + api: 'https://cloud.google.com/cloud-build/docs/api/reference/rest/' + description: | + Configuration for an automated build in response to source repository changes. + properties: + - !ruby/object:Api::Type::String + name: 'id' + description: | + The unique identifier for the trigger. + output: true + - !ruby/object:Api::Type::String + name: 'description' + description: | + Human-readable description of the trigger. + - !ruby/object:Api::Type::String + name: 'disabled' + description: | + Whether the trigger is disabled or not. If true, the trigger will never result in a build. + - !ruby/object:Api::Type::Time + name: 'createTime' + output: true + description: | + Time when the trigger was created. + - !ruby/object:Api::Type::KeyValuePairs + name: 'substitutions' + description: | + Substitutions data for Build resource. + - !ruby/object:Api::Type::String + name: 'filename' + conflicts: + - build + description: | + Path, from the source root, to a file whose contents is used for the template. + - !ruby/object:Api::Type::Array + name: 'ignoredFiles' + item_type: Api::Type::String + input: true + description: | + 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. + - !ruby/object:Api::Type::Array + name: 'includedFiles' + item_type: Api::Type::String + input: true + description: | + 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. + - !ruby/object:Api::Type::NestedObject + name: 'triggerTemplate' + description: | + 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. + properties: + - !ruby/object:Api::Type::String + name: 'projectId' + description: | + ID of the project that owns the Cloud Source Repository. If + omitted, the project ID requesting the build is assumed. + - !ruby/object:Api::Type::String + name: 'repoName' + default_value: 'default' + description: | + Name of the Cloud Source Repository. If omitted, the name "default" is assumed. + - !ruby/object:Api::Type::String + name: 'dir' + description: | + 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. + - !ruby/object:Api::Type::String + name: 'branchName' + description: | + Name of the branch to build. + - !ruby/object:Api::Type::String + name: 'tagName' + description: | + Name of the tag to build. + - !ruby/object:Api::Type::String + name: 'commitSha' + description: | + Explicit commit SHA to build. + - !ruby/object:Api::Type::NestedObject + name: 'build' + description: | + Contents of the build template. + properties: + - !ruby/object:Api::Type::Array + name: 'tags' + item_type: Api::Type::String + description: | + Tags for annotation of a Build. These are not docker tags. + - !ruby/object:Api::Type::Array + name: 'images' + item_type: Api::Type::String + description: | + 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. + - !ruby/object:Api::Type::Array + name: 'steps' + description: | + The operations to be performed on the workspace. + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: 'name' + description: | + 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. + - !ruby/object:Api::Type::Array + name: 'args' + item_type: Api::Type::String + description: | + 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. diff --git a/products/cloudbuild/terraform.yaml b/products/cloudbuild/terraform.yaml new file mode 100644 index 000000000000..9a10deb1b3a2 --- /dev/null +++ b/products/cloudbuild/terraform.yaml @@ -0,0 +1,42 @@ +# Copyright 2018 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Provider::Terraform::Config +overrides: !ruby/object:Provider::ResourceOverrides + Trigger: !ruby/object:Provider::Terraform::ResourceOverride + # import by default only works with old-style self links ending in a name + import_format: ["projects/{{project}}/triggers/{{trigger_id}}"] + id_format: '{{project}}/{{trigger_id}}' + self_link: 'projects/{{project}}/triggers/{{trigger_id}}' + example: + - !ruby/object:Provider::Terraform::Examples + name: "cloudbuild_trigger_filename" + primary_resource_id: "filename-trigger" + version: <%= version_name %> + properties: + id: !ruby/object:Provider::Terraform::PropertyOverride + name: 'trigger_id' + build.steps: !ruby/object:Provider::Terraform::PropertyOverride + name: 'step' + triggerTemplate.projectId: !ruby/object:Provider::Terraform::PropertyOverride + default_from_api: true + custom_code: !ruby/object:Provider::Terraform::CustomCode + post_create: templates/terraform/post_create/cloudbuild_trigger_id.go.erb + pre_update: templates/terraform/pre_update/cloudbuild_trigger.go.erb + resource_definition: templates/terraform/resource_definition/cloudbuild_trigger.go.erb +# This is for copying files over +files: !ruby/object:Provider::Config::Files + # These files have templating (ERB) code that will be run. + # This is usually to add licensing info, autogeneration notices, etc. + compile: +<%= lines(indent(compile('provider/terraform/product~compile.yaml'), 4)) -%> diff --git a/templates/terraform/examples/cloudbuild_trigger_filename.tf.erb b/templates/terraform/examples/cloudbuild_trigger_filename.tf.erb new file mode 100644 index 000000000000..3163bed5ed08 --- /dev/null +++ b/templates/terraform/examples/cloudbuild_trigger_filename.tf.erb @@ -0,0 +1,13 @@ +resource "google_cloudbuild_trigger" "<%= ctx[:primary_resource_id] %>" { + trigger_template { + branch_name = "master" + repo_name = "my-repo" + } + + substitutions = { + _FOO = "bar" + _BAZ = "qux" + } + + filename = "cloudbuild.yaml" +} diff --git a/templates/terraform/post_create/cloudbuild_trigger_id.go.erb b/templates/terraform/post_create/cloudbuild_trigger_id.go.erb new file mode 100644 index 000000000000..d57e2c82073e --- /dev/null +++ b/templates/terraform/post_create/cloudbuild_trigger_id.go.erb @@ -0,0 +1,14 @@ +// `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) diff --git a/templates/terraform/pre_update/cloudbuild_trigger.go.erb b/templates/terraform/pre_update/cloudbuild_trigger.go.erb new file mode 100644 index 000000000000..145ad821d145 --- /dev/null +++ b/templates/terraform/pre_update/cloudbuild_trigger.go.erb @@ -0,0 +1,15 @@ +<%- # the license inside this block applies to this file + # Copyright 2018 Google Inc. + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-%> + obj["id"] = d.Get("trigger_id") diff --git a/templates/terraform/resource_definition/cloudbuild_trigger.go.erb b/templates/terraform/resource_definition/cloudbuild_trigger.go.erb new file mode 100644 index 000000000000..96aa57f3cf0a --- /dev/null +++ b/templates/terraform/resource_definition/cloudbuild_trigger.go.erb @@ -0,0 +1,15 @@ +<%# The license inside this block applies to this file. + # Copyright 2017 Google Inc. + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-%> +SchemaVersion: 1, diff --git a/third_party/terraform/resources/resource_cloudbuild_build_trigger.go b/third_party/terraform/resources/resource_cloudbuild_build_trigger.go deleted file mode 100644 index 3af669fc7b15..000000000000 --- a/third_party/terraform/resources/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/third_party/terraform/tests/resource_cloudbuild_build_trigger_test.go b/third_party/terraform/tests/resource_cloudbuild_build_trigger_test.go index 67b9201af211..0cbda174a424 100644 --- a/third_party/terraform/tests/resource_cloudbuild_build_trigger_test.go +++ b/third_party/terraform/tests/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"), - ), - }, - { - ResourceName: "google_cloudbuild_trigger.build_trigger", - ImportState: true, - ImportStateVerify: true, - ImportStateIdPrefix: fmt.Sprintf("%s/", projectID), + Config: testGoogleCloudBuildTrigger_basic(), }, { - Config: testGoogleCloudBuildTrigger_updated(projectID, projectOrg, projectBillingAccount), + ResourceName: "google_cloudbuild_trigger.build_trigger", + ImportState: true, + ImportStateVerify: true, }, { - ResourceName: "google_cloudbuild_trigger.build_trigger", - ImportState: true, - ImportStateVerify: true, - ImportStateIdPrefix: fmt.Sprintf("%s/", projectID), + Config: testGoogleCloudBuildTrigger_updated(), }, { - 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/third_party/terraform/utils/provider.go.erb b/third_party/terraform/utils/provider.go.erb index df6d8204228c..0484d8eb4d6b 100644 --- a/third_party/terraform/utils/provider.go.erb +++ b/third_party/terraform/utils/provider.go.erb @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "github.com/terraform-providers/terraform-provider-google-beta/google-beta" + google2 "github.com/terraform-providers/terraform-provider-google/google" "os" "github.com/hashicorp/terraform/helper/mutexkv" @@ -127,6 +128,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { <% end -%> GeneratedAppengineResourcesMap, GeneratedComputeResourcesMap, + GeneratedCloudbuildResourcesMap, GeneratedDnsResourcesMap, GeneratedRedisResourcesMap, GeneratedResourceManagerResourcesMap, @@ -142,7 +144,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/third_party/terraform/utils/utils.go b/third_party/terraform/utils/utils.go index 3c1bde657397..305ee7ef86c2 100644 --- a/third_party/terraform/utils/utils.go +++ b/third_party/terraform/utils/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/third_party/terraform/website/docs/r/cloudbuild_trigger.html.markdown b/third_party/terraform/website/docs/r/cloudbuild_trigger.html.markdown deleted file mode 100644 index d5694d5bfcfa..000000000000 --- a/third_party/terraform/website/docs/r/cloudbuild_trigger.html.markdown +++ /dev/null @@ -1,157 +0,0 @@ ---- -layout: "google" -page_title: "Google: google_cloudbuild_trigger" -sidebar_current: "docs-google-cloudbuild-trigger" -description: |- - Creates a new build trigger within GCR. ---- - -# 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). - -## Example Usage - -```hcl -resource "google_cloudbuild_trigger" "build_trigger" { - project = "my-project" - trigger_template { - branch_name = "master" - project = "my-project" - repo_name = "some-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" - } - 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. - -* `project` - (Optional) The ID of the project that the trigger will be created in. -Defaults to the provider project configuration. - -* `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. - -* `trigger_template` - (Optional) Location of the source in a Google -Cloud Source Repository. Structure is documented below. - ---- - -The `build` block supports: - -* `images` - (Optional) A list of images to be pushed upon the successful -completion of all build steps. - -* `step` - (Optional) The operations to be performed on the workspace. -Structure is documented below. - -* `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. - -* `commit_sha` - (Optional) Explicit commit SHA to build. - -* `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. - -* `repo_name` - (Optional) Name of the Cloud Source Repository. - -* `tag_name` - (Optional) Name of the tag to build. -