From b72dbe1e47bbc2ec27121946e06c154a72ab678a Mon Sep 17 00:00:00 2001 From: The Magician Date: Wed, 5 Aug 2020 10:10:19 -0700 Subject: [PATCH] Adding Missing Cloud Build Attributes (#3627) (#2335) Signed-off-by: Modular Magician --- .changelog/3627.txt | 3 + google-beta/resource_cloud_build_trigger.go | 599 ++++++++++++++++++ ...urce_cloud_build_trigger_generated_test.go | 63 ++ .../resource_cloudbuild_trigger_test.go | 1 + .../docs/r/cloudbuild_trigger.html.markdown | 158 +++++ 5 files changed, 824 insertions(+) create mode 100644 .changelog/3627.txt diff --git a/.changelog/3627.txt b/.changelog/3627.txt new file mode 100644 index 0000000000..45ea352c57 --- /dev/null +++ b/.changelog/3627.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +cloudbuild: added tags, source, queue_ttl, logs_bucket, substitutions, and secrets to `google_cloudbuild_trigger` +``` diff --git a/google-beta/resource_cloud_build_trigger.go b/google-beta/resource_cloud_build_trigger.go index cc8156bea9..1f110e2a34 100644 --- a/google-beta/resource_cloud_build_trigger.go +++ b/google-beta/resource_cloud_build_trigger.go @@ -251,6 +251,146 @@ If any of the images fail to be pushed, the build status is marked FAILURE.`, Type: schema.TypeString, }, }, + "logs_bucket": { + Type: schema.TypeString, + Optional: true, + Description: `Google Cloud Storage bucket where logs should be written. +Logs file names will be of the format ${logsBucket}/log-${build_id}.txt.`, + }, + "queue_ttl": { + Type: schema.TypeString, + Optional: true, + Description: `TTL in queue for this build. If provided and the build is enqueued longer than this value, +the build will expire and the build status will be EXPIRED. +The TTL starts ticking from createTime. +A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s".`, + }, + "secret": { + Type: schema.TypeList, + Optional: true, + Description: `Secrets to decrypt using Cloud Key Management Service.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_key_name": { + Type: schema.TypeString, + Required: true, + Description: `Cloud KMS key name to use to decrypt these envs.`, + }, + "secret_env": { + Type: schema.TypeMap, + Optional: true, + Description: `Map of environment variable name to its encrypted value. +Secret environment variables must be unique across all of a build's secrets, +and must be used by at least one build step. Values can be at most 64 KB in size. +There can be at most 100 secret values across all of a build's secrets.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "source": { + Type: schema.TypeList, + Optional: true, + Description: `The location of the source files to build. + +One of 'storageSource' or 'repoSource' must be provided.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repo_source": { + Type: schema.TypeList, + Optional: true, + Description: `Location of the source in a Google Cloud Source Repository.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repo_name": { + Type: schema.TypeString, + Required: true, + Description: `Name of the Cloud Source Repository.`, + }, + "branch_name": { + Type: schema.TypeString, + Optional: true, + Description: `Regex matching branches to build. Exactly one a of branch name, tag, or commit SHA must be provided. +The syntax of the regular expressions accepted is the syntax accepted by RE2 and +described at https://github.com/google/re2/wiki/Syntax`, + }, + "commit_sha": { + Type: schema.TypeString, + Optional: true, + Description: `Explicit commit SHA to build. Exactly one a of branch name, tag, or commit SHA must be provided.`, + }, + "dir": { + Type: schema.TypeString, + Optional: true, + 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.`, + }, + "invert_regex": { + Type: schema.TypeBool, + Optional: true, + Description: `Only trigger a build if the revision regex does NOT match the revision regex.`, + }, + "project_id": { + Type: schema.TypeString, + Optional: true, + Description: `ID of the project that owns the Cloud Source Repository. +If omitted, the project ID requesting the build is assumed.`, + }, + "substitutions": { + Type: schema.TypeMap, + Optional: true, + Description: `Substitutions to use in a triggered build. Should only be used with triggers.run`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tag_name": { + Type: schema.TypeString, + Optional: true, + Description: `Regex matching tags to build. Exactly one a of branch name, tag, or commit SHA must be provided. +The syntax of the regular expressions accepted is the syntax accepted by RE2 and +described at https://github.com/google/re2/wiki/Syntax`, + }, + }, + }, + }, + "storage_source": { + Type: schema.TypeList, + Optional: true, + Description: `Location of the source in an archive file in Google Cloud Storage.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bucket": { + Type: schema.TypeString, + Required: true, + Description: `Google Cloud Storage bucket containing the source.`, + }, + "object": { + Type: schema.TypeString, + Required: true, + Description: `Google Cloud Storage object containing the source. +This object must be a gzipped archive file (.tar.gz) containing source to build.`, + }, + "generation": { + Type: schema.TypeString, + Optional: true, + Description: `Google Cloud Storage generation for the object. +If the generation is omitted, the latest generation will be used`, + }, + }, + }, + }, + }, + }, + }, + "substitutions": { + Type: schema.TypeMap, + Optional: true, + Description: `Substitutions data for Build resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "tags": { Type: schema.TypeList, Optional: true, @@ -415,6 +555,14 @@ a build.`, Description: `Substitutions data for Build resource.`, Elem: &schema.Schema{Type: schema.TypeString}, }, + "tags": { + Type: schema.TypeList, + Optional: true, + Description: `Tags for annotation of a BuildTrigger`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, "trigger_template": { Type: schema.TypeList, Optional: true, @@ -514,6 +662,12 @@ func resourceCloudBuildTriggerCreate(d *schema.ResourceData, meta interface{}) e } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { obj["description"] = descriptionProp } + tagsProp, err := expandCloudBuildTriggerTags(d.Get("tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("tags"); !isEmptyValue(reflect.ValueOf(tagsProp)) && (ok || !reflect.DeepEqual(v, tagsProp)) { + obj["tags"] = tagsProp + } disabledProp, err := expandCloudBuildTriggerDisabled(d.Get("disabled"), d, config) if err != nil { return err @@ -635,6 +789,9 @@ func resourceCloudBuildTriggerRead(d *schema.ResourceData, meta interface{}) err if err := d.Set("description", flattenCloudBuildTriggerDescription(res["description"], d, config)); err != nil { return fmt.Errorf("Error reading Trigger: %s", err) } + if err := d.Set("tags", flattenCloudBuildTriggerTags(res["tags"], d, config)); err != nil { + return fmt.Errorf("Error reading Trigger: %s", err) + } if err := d.Set("disabled", flattenCloudBuildTriggerDisabled(res["disabled"], d, config)); err != nil { return fmt.Errorf("Error reading Trigger: %s", err) } @@ -687,6 +844,12 @@ func resourceCloudBuildTriggerUpdate(d *schema.ResourceData, meta interface{}) e } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { obj["description"] = descriptionProp } + tagsProp, err := expandCloudBuildTriggerTags(d.Get("tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("tags"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, tagsProp)) { + obj["tags"] = tagsProp + } disabledProp, err := expandCloudBuildTriggerDisabled(d.Get("disabled"), d, config) if err != nil { return err @@ -811,6 +974,10 @@ func flattenCloudBuildTriggerDescription(v interface{}, d *schema.ResourceData, return v } +func flattenCloudBuildTriggerTags(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenCloudBuildTriggerDisabled(v interface{}, d *schema.ResourceData, config *Config) interface{} { return v } @@ -982,16 +1149,129 @@ func flattenCloudBuildTriggerBuild(v interface{}, d *schema.ResourceData, config return nil } transformed := make(map[string]interface{}) + transformed["source"] = + flattenCloudBuildTriggerBuildSource(original["source"], d, config) transformed["tags"] = flattenCloudBuildTriggerBuildTags(original["tags"], d, config) transformed["images"] = flattenCloudBuildTriggerBuildImages(original["images"], d, config) + transformed["substitutions"] = + flattenCloudBuildTriggerBuildSubstitutions(original["substitutions"], d, config) + transformed["queue_ttl"] = + flattenCloudBuildTriggerBuildQueueTtl(original["queueTtl"], d, config) + transformed["logs_bucket"] = + flattenCloudBuildTriggerBuildLogsBucket(original["logsBucket"], d, config) transformed["timeout"] = flattenCloudBuildTriggerBuildTimeout(original["timeout"], d, config) + transformed["secret"] = + flattenCloudBuildTriggerBuildSecret(original["secrets"], d, config) transformed["step"] = flattenCloudBuildTriggerBuildStep(original["steps"], d, config) return []interface{}{transformed} } +func flattenCloudBuildTriggerBuildSource(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["storage_source"] = + flattenCloudBuildTriggerBuildSourceStorageSource(original["storageSource"], d, config) + transformed["repo_source"] = + flattenCloudBuildTriggerBuildSourceRepoSource(original["repoSource"], d, config) + return []interface{}{transformed} +} +func flattenCloudBuildTriggerBuildSourceStorageSource(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["bucket"] = + flattenCloudBuildTriggerBuildSourceStorageSourceBucket(original["bucket"], d, config) + transformed["object"] = + flattenCloudBuildTriggerBuildSourceStorageSourceObject(original["object"], d, config) + transformed["generation"] = + flattenCloudBuildTriggerBuildSourceStorageSourceGeneration(original["generation"], d, config) + return []interface{}{transformed} +} +func flattenCloudBuildTriggerBuildSourceStorageSourceBucket(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceStorageSourceObject(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceStorageSourceGeneration(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSource(v interface{}, d *schema.ResourceData, config *Config) 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"] = + flattenCloudBuildTriggerBuildSourceRepoSourceProjectId(original["projectId"], d, config) + transformed["repo_name"] = + flattenCloudBuildTriggerBuildSourceRepoSourceRepoName(original["repoName"], d, config) + transformed["dir"] = + flattenCloudBuildTriggerBuildSourceRepoSourceDir(original["dir"], d, config) + transformed["invert_regex"] = + flattenCloudBuildTriggerBuildSourceRepoSourceInvertRegex(original["invertRegex"], d, config) + transformed["substitutions"] = + flattenCloudBuildTriggerBuildSourceRepoSourceSubstitutions(original["substitutions"], d, config) + transformed["branch_name"] = + flattenCloudBuildTriggerBuildSourceRepoSourceBranchName(original["branchName"], d, config) + transformed["tag_name"] = + flattenCloudBuildTriggerBuildSourceRepoSourceTagName(original["tagName"], d, config) + transformed["commit_sha"] = + flattenCloudBuildTriggerBuildSourceRepoSourceCommitSha(original["commitSha"], d, config) + return []interface{}{transformed} +} +func flattenCloudBuildTriggerBuildSourceRepoSourceProjectId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceRepoName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceDir(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceInvertRegex(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceSubstitutions(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceBranchName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceTagName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSourceRepoSourceCommitSha(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenCloudBuildTriggerBuildTags(v interface{}, d *schema.ResourceData, config *Config) interface{} { return v } @@ -1000,10 +1280,49 @@ func flattenCloudBuildTriggerBuildImages(v interface{}, d *schema.ResourceData, return v } +func flattenCloudBuildTriggerBuildSubstitutions(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildQueueTtl(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildLogsBucket(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenCloudBuildTriggerBuildTimeout(v interface{}, d *schema.ResourceData, config *Config) interface{} { return v } +func flattenCloudBuildTriggerBuildSecret(v interface{}, d *schema.ResourceData, config *Config) 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{}{ + "kms_key_name": flattenCloudBuildTriggerBuildSecretKmsKeyName(original["kmsKeyName"], d, config), + "secret_env": flattenCloudBuildTriggerBuildSecretSecretEnv(original["secretEnv"], d, config), + }) + } + return transformed +} +func flattenCloudBuildTriggerBuildSecretKmsKeyName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudBuildTriggerBuildSecretSecretEnv(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenCloudBuildTriggerBuildStep(v interface{}, d *schema.ResourceData, config *Config) interface{} { if v == nil { return v @@ -1107,6 +1426,10 @@ func expandCloudBuildTriggerDescription(v interface{}, d TerraformResourceData, return v, nil } +func expandCloudBuildTriggerTags(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandCloudBuildTriggerDisabled(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -1370,6 +1693,13 @@ func expandCloudBuildTriggerBuild(v interface{}, d TerraformResourceData, config original := raw.(map[string]interface{}) transformed := make(map[string]interface{}) + transformedSource, err := expandCloudBuildTriggerBuildSource(original["source"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSource); val.IsValid() && !isEmptyValue(val) { + transformed["source"] = transformedSource + } + transformedTags, err := expandCloudBuildTriggerBuildTags(original["tags"], d, config) if err != nil { return nil, err @@ -1384,6 +1714,27 @@ func expandCloudBuildTriggerBuild(v interface{}, d TerraformResourceData, config transformed["images"] = transformedImages } + transformedSubstitutions, err := expandCloudBuildTriggerBuildSubstitutions(original["substitutions"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSubstitutions); val.IsValid() && !isEmptyValue(val) { + transformed["substitutions"] = transformedSubstitutions + } + + transformedQueueTtl, err := expandCloudBuildTriggerBuildQueueTtl(original["queue_ttl"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedQueueTtl); val.IsValid() && !isEmptyValue(val) { + transformed["queueTtl"] = transformedQueueTtl + } + + transformedLogsBucket, err := expandCloudBuildTriggerBuildLogsBucket(original["logs_bucket"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLogsBucket); val.IsValid() && !isEmptyValue(val) { + transformed["logsBucket"] = transformedLogsBucket + } + transformedTimeout, err := expandCloudBuildTriggerBuildTimeout(original["timeout"], d, config) if err != nil { return nil, err @@ -1391,6 +1742,13 @@ func expandCloudBuildTriggerBuild(v interface{}, d TerraformResourceData, config transformed["timeout"] = transformedTimeout } + transformedSecret, err := expandCloudBuildTriggerBuildSecret(original["secret"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSecret); val.IsValid() && !isEmptyValue(val) { + transformed["secrets"] = transformedSecret + } + transformedStep, err := expandCloudBuildTriggerBuildStep(original["step"], d, config) if err != nil { return nil, err @@ -1401,6 +1759,184 @@ func expandCloudBuildTriggerBuild(v interface{}, d TerraformResourceData, config return transformed, nil } +func expandCloudBuildTriggerBuildSource(v interface{}, d TerraformResourceData, 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{}) + + transformedStorageSource, err := expandCloudBuildTriggerBuildSourceStorageSource(original["storage_source"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStorageSource); val.IsValid() && !isEmptyValue(val) { + transformed["storageSource"] = transformedStorageSource + } + + transformedRepoSource, err := expandCloudBuildTriggerBuildSourceRepoSource(original["repo_source"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRepoSource); val.IsValid() && !isEmptyValue(val) { + transformed["repoSource"] = transformedRepoSource + } + + return transformed, nil +} + +func expandCloudBuildTriggerBuildSourceStorageSource(v interface{}, d TerraformResourceData, 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{}) + + transformedBucket, err := expandCloudBuildTriggerBuildSourceStorageSourceBucket(original["bucket"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedBucket); val.IsValid() && !isEmptyValue(val) { + transformed["bucket"] = transformedBucket + } + + transformedObject, err := expandCloudBuildTriggerBuildSourceStorageSourceObject(original["object"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedObject); val.IsValid() && !isEmptyValue(val) { + transformed["object"] = transformedObject + } + + transformedGeneration, err := expandCloudBuildTriggerBuildSourceStorageSourceGeneration(original["generation"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedGeneration); val.IsValid() && !isEmptyValue(val) { + transformed["generation"] = transformedGeneration + } + + return transformed, nil +} + +func expandCloudBuildTriggerBuildSourceStorageSourceBucket(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceStorageSourceObject(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceStorageSourceGeneration(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSource(v interface{}, d TerraformResourceData, 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 := expandCloudBuildTriggerBuildSourceRepoSourceProjectId(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 := expandCloudBuildTriggerBuildSourceRepoSourceRepoName(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 := expandCloudBuildTriggerBuildSourceRepoSourceDir(original["dir"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDir); val.IsValid() && !isEmptyValue(val) { + transformed["dir"] = transformedDir + } + + transformedInvertRegex, err := expandCloudBuildTriggerBuildSourceRepoSourceInvertRegex(original["invert_regex"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInvertRegex); val.IsValid() && !isEmptyValue(val) { + transformed["invertRegex"] = transformedInvertRegex + } + + transformedSubstitutions, err := expandCloudBuildTriggerBuildSourceRepoSourceSubstitutions(original["substitutions"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSubstitutions); val.IsValid() && !isEmptyValue(val) { + transformed["substitutions"] = transformedSubstitutions + } + + transformedBranchName, err := expandCloudBuildTriggerBuildSourceRepoSourceBranchName(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 := expandCloudBuildTriggerBuildSourceRepoSourceTagName(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 := expandCloudBuildTriggerBuildSourceRepoSourceCommitSha(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 expandCloudBuildTriggerBuildSourceRepoSourceProjectId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSourceRepoName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSourceDir(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSourceInvertRegex(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSourceSubstitutions(v interface{}, d TerraformResourceData, 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 expandCloudBuildTriggerBuildSourceRepoSourceBranchName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSourceTagName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSourceRepoSourceCommitSha(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandCloudBuildTriggerBuildTags(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -1409,10 +1945,73 @@ func expandCloudBuildTriggerBuildImages(v interface{}, d TerraformResourceData, return v, nil } +func expandCloudBuildTriggerBuildSubstitutions(v interface{}, d TerraformResourceData, 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 expandCloudBuildTriggerBuildQueueTtl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildLogsBucket(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandCloudBuildTriggerBuildTimeout(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } +func expandCloudBuildTriggerBuildSecret(v interface{}, d TerraformResourceData, 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{}) + + transformedKmsKeyName, err := expandCloudBuildTriggerBuildSecretKmsKeyName(original["kms_key_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKmsKeyName); val.IsValid() && !isEmptyValue(val) { + transformed["kmsKeyName"] = transformedKmsKeyName + } + + transformedSecretEnv, err := expandCloudBuildTriggerBuildSecretSecretEnv(original["secret_env"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSecretEnv); val.IsValid() && !isEmptyValue(val) { + transformed["secretEnv"] = transformedSecretEnv + } + + req = append(req, transformed) + } + return req, nil +} + +func expandCloudBuildTriggerBuildSecretKmsKeyName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudBuildTriggerBuildSecretSecretEnv(v interface{}, d TerraformResourceData, 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 expandCloudBuildTriggerBuildStep(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { l := v.([]interface{}) req := make([]interface{}, 0, len(l)) diff --git a/google-beta/resource_cloud_build_trigger_generated_test.go b/google-beta/resource_cloud_build_trigger_generated_test.go index a86f7fc133..fae7537d3f 100644 --- a/google-beta/resource_cloud_build_trigger_generated_test.go +++ b/google-beta/resource_cloud_build_trigger_generated_test.go @@ -65,6 +65,69 @@ resource "google_cloudbuild_trigger" "filename-trigger" { `, context) } +func TestAccCloudBuildTrigger_cloudbuildTriggerBuildExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudBuildTriggerDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudBuildTrigger_cloudbuildTriggerBuildExample(context), + }, + { + ResourceName: "google_cloudbuild_trigger.build-trigger", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCloudBuildTrigger_cloudbuildTriggerBuildExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloudbuild_trigger" "build-trigger" { + trigger_template { + branch_name = "master" + repo_name = "my-repo" + } + + build { + step { + name = "gcr.io/cloud-builders/gsutil" + args = ["cp", "gs://mybucket/remotefile.zip", "localfile.zip"] + timeout = "120s" + } + + source { + storage_source { + bucket = "mybucket" + object = "source_code.tar.gz" + } + } + tags = ["build", "newFeature"] + substitutions = { + _FOO = "bar" + _BAZ = "qux" + } + queue_ttl = "20s" + logs_bucket = "gs://mybucket/logs" + secret { + kms_key_name = "projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name" + secret_env = { + PASSWORD = "ZW5jcnlwdGVkLXBhc3N3b3JkCg==" + } + } + } +} +`, context) +} + func testAccCheckCloudBuildTriggerDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/google-beta/resource_cloudbuild_trigger_test.go b/google-beta/resource_cloudbuild_trigger_test.go index e00c347f4a..218d02030d 100644 --- a/google-beta/resource_cloudbuild_trigger_test.go +++ b/google-beta/resource_cloudbuild_trigger_test.go @@ -248,6 +248,7 @@ resource "google_cloudbuild_trigger" "build_trigger" { args = ["test"] timeout = "300s" } + logs_bucket = "gs://mybucket/logs" } } `, name) diff --git a/website/docs/r/cloudbuild_trigger.html.markdown b/website/docs/r/cloudbuild_trigger.html.markdown index 7953e3d600..af87f569fc 100644 --- a/website/docs/r/cloudbuild_trigger.html.markdown +++ b/website/docs/r/cloudbuild_trigger.html.markdown @@ -54,6 +54,50 @@ resource "google_cloudbuild_trigger" "filename-trigger" { filename = "cloudbuild.yaml" } ``` + +## Example Usage - Cloudbuild Trigger Build + + +```hcl +resource "google_cloudbuild_trigger" "build-trigger" { + trigger_template { + branch_name = "master" + repo_name = "my-repo" + } + + build { + step { + name = "gcr.io/cloud-builders/gsutil" + args = ["cp", "gs://mybucket/remotefile.zip", "localfile.zip"] + timeout = "120s" + } + + source { + storage_source { + bucket = "mybucket" + object = "source_code.tar.gz" + } + } + tags = ["build", "newFeature"] + substitutions = { + _FOO = "bar" + _BAZ = "qux" + } + queue_ttl = "20s" + logs_bucket = "gs://mybucket/logs" + secret { + kms_key_name = "projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name" + secret_env = { + PASSWORD = "ZW5jcnlwdGVkLXBhc3N3b3JkCg==" + } + } + } +} +``` ## Argument Reference @@ -72,6 +116,10 @@ The following arguments are supported: (Optional) Human-readable description of the trigger. +* `tags` - + (Optional) + Tags for annotation of a BuildTrigger + * `disabled` - (Optional) Whether the trigger is disabled or not. If true, the trigger will never result in a build. @@ -220,6 +268,12 @@ The `push` block supports: The `build` block supports: +* `source` - + (Optional) + The location of the source files to build. + One of `storageSource` or `repoSource` must be provided. + Structure is documented below. + * `tags` - (Optional) Tags for annotation of a Build. These are not docker tags. @@ -231,6 +285,22 @@ The `build` block supports: 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. +* `substitutions` - + (Optional) + Substitutions data for Build resource. + +* `queue_ttl` - + (Optional) + TTL in queue for this build. If provided and the build is enqueued longer than this value, + the build will expire and the build status will be EXPIRED. + The TTL starts ticking from createTime. + A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s". + +* `logs_bucket` - + (Optional) + Google Cloud Storage bucket where logs should be written. + Logs file names will be of the format ${logsBucket}/log-${build_id}.txt. + * `timeout` - (Optional) Amount of time that this build should be allowed to run, to second granularity. @@ -239,12 +309,100 @@ The `build` block supports: The expected format is the number of seconds followed by s. Default time is ten minutes (600s). +* `secret` - + (Optional) + Secrets to decrypt using Cloud Key Management Service. + Structure is documented below. + * `step` - (Required) The operations to be performed on the workspace. Structure is documented below. +The `source` block supports: + +* `storage_source` - + (Optional) + Location of the source in an archive file in Google Cloud Storage. + Structure is documented below. + +* `repo_source` - + (Optional) + Location of the source in a Google Cloud Source Repository. + Structure is documented below. + + +The `storage_source` block supports: + +* `bucket` - + (Required) + Google Cloud Storage bucket containing the source. + +* `object` - + (Required) + Google Cloud Storage object containing the source. + This object must be a gzipped archive file (.tar.gz) containing source to build. + +* `generation` - + (Optional) + Google Cloud Storage generation for the object. + If the generation is omitted, the latest generation will be used + +The `repo_source` block supports: + +* `project_id` - + (Optional) + ID of the project that owns the Cloud Source Repository. + If omitted, the project ID requesting the build is assumed. + +* `repo_name` - + (Required) + Name of the Cloud Source Repository. + +* `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. + +* `invert_regex` - + (Optional) + Only trigger a build if the revision regex does NOT match the revision regex. + +* `substitutions` - + (Optional) + Substitutions to use in a triggered build. Should only be used with triggers.run + +* `branch_name` - + (Optional) + Regex matching branches to build. Exactly one a of branch name, tag, or commit SHA must be provided. + The syntax of the regular expressions accepted is the syntax accepted by RE2 and + described at https://github.com/google/re2/wiki/Syntax + +* `tag_name` - + (Optional) + Regex matching tags to build. Exactly one a of branch name, tag, or commit SHA must be provided. + The syntax of the regular expressions accepted is the syntax accepted by RE2 and + described at https://github.com/google/re2/wiki/Syntax + +* `commit_sha` - + (Optional) + Explicit commit SHA to build. Exactly one a of branch name, tag, or commit SHA must be provided. + +The `secret` block supports: + +* `kms_key_name` - + (Required) + Cloud KMS key name to use to decrypt these envs. + +* `secret_env` - + (Optional) + Map of environment variable name to its encrypted value. + Secret environment variables must be unique across all of a build's secrets, + and must be used by at least one build step. Values can be at most 64 KB in size. + There can be at most 100 secret values across all of a build's secrets. + The `step` block supports: * `name` -