From fff2b70d0701b8e61ca9f89a434db5074b78147d Mon Sep 17 00:00:00 2001 From: The Magician Date: Mon, 7 Oct 2024 12:33:43 -0700 Subject: [PATCH] adding new google_secure_source_manager_branch_rule resource (#11709) (#19773) [upstream:55d45c535ff09145223f3f5f62c52fb1053de30b] Signed-off-by: Modular Magician --- .changelog/11709.txt | 3 + google/provider/provider_mmv1_resources.go | 5 +- ...ource_secure_source_manager_branch_rule.go | 660 ++++++++++++++++++ ...urce_manager_branch_rule_generated_test.go | 190 +++++ ...cure_source_manager_branch_rule_sweeper.go | 143 ++++ ..._source_manager_branch_rule_update_test.go | 114 +++ ...e_source_manager_branch_rule.html.markdown | 224 ++++++ 7 files changed, 1337 insertions(+), 2 deletions(-) create mode 100644 .changelog/11709.txt create mode 100644 google/services/securesourcemanager/resource_secure_source_manager_branch_rule.go create mode 100644 google/services/securesourcemanager/resource_secure_source_manager_branch_rule_generated_test.go create mode 100644 google/services/securesourcemanager/resource_secure_source_manager_branch_rule_sweeper.go create mode 100644 google/services/securesourcemanager/resource_secure_source_manager_branch_rule_update_test.go create mode 100644 website/docs/r/secure_source_manager_branch_rule.html.markdown diff --git a/.changelog/11709.txt b/.changelog/11709.txt new file mode 100644 index 00000000000..1423312115f --- /dev/null +++ b/.changelog/11709.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_secure_source_manager_branch_rule` +``` \ No newline at end of file diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index 49f8324d139..2f4cd97af6b 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -437,9 +437,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 468 +// Generated resources: 469 // Generated IAM resources: 261 -// Total generated resources: 729 +// Total generated resources: 730 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -1043,6 +1043,7 @@ var generatedResources = map[string]*schema.Resource{ "google_secret_manager_regional_secret_iam_member": tpgiamresource.ResourceIamMember(secretmanagerregional.SecretManagerRegionalRegionalSecretIamSchema, secretmanagerregional.SecretManagerRegionalRegionalSecretIamUpdaterProducer, secretmanagerregional.SecretManagerRegionalRegionalSecretIdParseFunc), "google_secret_manager_regional_secret_iam_policy": tpgiamresource.ResourceIamPolicy(secretmanagerregional.SecretManagerRegionalRegionalSecretIamSchema, secretmanagerregional.SecretManagerRegionalRegionalSecretIamUpdaterProducer, secretmanagerregional.SecretManagerRegionalRegionalSecretIdParseFunc), "google_secret_manager_regional_secret_version": secretmanagerregional.ResourceSecretManagerRegionalRegionalSecretVersion(), + "google_secure_source_manager_branch_rule": securesourcemanager.ResourceSecureSourceManagerBranchRule(), "google_secure_source_manager_instance": securesourcemanager.ResourceSecureSourceManagerInstance(), "google_secure_source_manager_instance_iam_binding": tpgiamresource.ResourceIamBinding(securesourcemanager.SecureSourceManagerInstanceIamSchema, securesourcemanager.SecureSourceManagerInstanceIamUpdaterProducer, securesourcemanager.SecureSourceManagerInstanceIdParseFunc), "google_secure_source_manager_instance_iam_member": tpgiamresource.ResourceIamMember(securesourcemanager.SecureSourceManagerInstanceIamSchema, securesourcemanager.SecureSourceManagerInstanceIamUpdaterProducer, securesourcemanager.SecureSourceManagerInstanceIdParseFunc), diff --git a/google/services/securesourcemanager/resource_secure_source_manager_branch_rule.go b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule.go new file mode 100644 index 00000000000..7702c81f29c --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule.go @@ -0,0 +1,660 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 securesourcemanager + +import ( + "fmt" + "log" + "net/http" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func ResourceSecureSourceManagerBranchRule() *schema.Resource { + return &schema.Resource{ + Create: resourceSecureSourceManagerBranchRuleCreate, + Read: resourceSecureSourceManagerBranchRuleRead, + Update: resourceSecureSourceManagerBranchRuleUpdate, + Delete: resourceSecureSourceManagerBranchRuleDelete, + + Importer: &schema.ResourceImporter{ + State: resourceSecureSourceManagerBranchRuleImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "branch_rule_id": { + Type: schema.TypeString, + Required: true, + Description: `The ID for the BranchRule.`, + }, + "include_pattern": { + Type: schema.TypeString, + Required: true, + Description: `The BranchRule matches branches based on the specified regular expression. Use .* to match all branches.`, + }, + "location": { + Type: schema.TypeString, + Required: true, + Description: `The location for the Repository.`, + }, + "repository_id": { + Type: schema.TypeString, + Required: true, + Description: `The ID for the Repository.`, + }, + "allow_stale_reviews": { + Type: schema.TypeBool, + Optional: true, + Description: `Determines if allow stale reviews or approvals before merging to the branch.`, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + Description: `Determines if the branch rule is disabled or not.`, + }, + "minimum_approvals_count": { + Type: schema.TypeInt, + Optional: true, + Description: `The minimum number of approvals required for the branch rule to be matched.`, + }, + "minimum_reviews_count": { + Type: schema.TypeInt, + Optional: true, + Description: `The minimum number of reviews required for the branch rule to be matched.`, + }, + "require_comments_resolved": { + Type: schema.TypeBool, + Optional: true, + Description: `Determines if require comments resolved before merging to the branch.`, + }, + "require_linear_history": { + Type: schema.TypeBool, + Optional: true, + Description: `Determines if require linear history before merging to the branch.`, + }, + "require_pull_request": { + Type: schema.TypeBool, + Optional: true, + Description: `Determines if the branch rule requires a pull request or not.`, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `Time the BranchRule was created in UTC.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name for the BranchRule.`, + }, + "uid": { + Type: schema.TypeString, + Computed: true, + Description: `Unique identifier of the BranchRule.`, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `Time the BranchRule was updated in UTC.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceSecureSourceManagerBranchRuleCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + includePatternProp, err := expandSecureSourceManagerBranchRuleIncludePattern(d.Get("include_pattern"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("include_pattern"); !tpgresource.IsEmptyValue(reflect.ValueOf(includePatternProp)) && (ok || !reflect.DeepEqual(v, includePatternProp)) { + obj["includePattern"] = includePatternProp + } + disabledProp, err := expandSecureSourceManagerBranchRuleDisabled(d.Get("disabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("disabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(disabledProp)) && (ok || !reflect.DeepEqual(v, disabledProp)) { + obj["disabled"] = disabledProp + } + requirePullRequestProp, err := expandSecureSourceManagerBranchRuleRequirePullRequest(d.Get("require_pull_request"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("require_pull_request"); !tpgresource.IsEmptyValue(reflect.ValueOf(requirePullRequestProp)) && (ok || !reflect.DeepEqual(v, requirePullRequestProp)) { + obj["requirePullRequest"] = requirePullRequestProp + } + minimumReviewsCountProp, err := expandSecureSourceManagerBranchRuleMinimumReviewsCount(d.Get("minimum_reviews_count"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("minimum_reviews_count"); !tpgresource.IsEmptyValue(reflect.ValueOf(minimumReviewsCountProp)) && (ok || !reflect.DeepEqual(v, minimumReviewsCountProp)) { + obj["minimumReviewsCount"] = minimumReviewsCountProp + } + minimumApprovalsCountProp, err := expandSecureSourceManagerBranchRuleMinimumApprovalsCount(d.Get("minimum_approvals_count"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("minimum_approvals_count"); !tpgresource.IsEmptyValue(reflect.ValueOf(minimumApprovalsCountProp)) && (ok || !reflect.DeepEqual(v, minimumApprovalsCountProp)) { + obj["minimumApprovalsCount"] = minimumApprovalsCountProp + } + requireCommentsResolvedProp, err := expandSecureSourceManagerBranchRuleRequireCommentsResolved(d.Get("require_comments_resolved"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("require_comments_resolved"); !tpgresource.IsEmptyValue(reflect.ValueOf(requireCommentsResolvedProp)) && (ok || !reflect.DeepEqual(v, requireCommentsResolvedProp)) { + obj["requireCommentsResolved"] = requireCommentsResolvedProp + } + allowStaleReviewsProp, err := expandSecureSourceManagerBranchRuleAllowStaleReviews(d.Get("allow_stale_reviews"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("allow_stale_reviews"); !tpgresource.IsEmptyValue(reflect.ValueOf(allowStaleReviewsProp)) && (ok || !reflect.DeepEqual(v, allowStaleReviewsProp)) { + obj["allowStaleReviews"] = allowStaleReviewsProp + } + requireLinearHistoryProp, err := expandSecureSourceManagerBranchRuleRequireLinearHistory(d.Get("require_linear_history"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("require_linear_history"); !tpgresource.IsEmptyValue(reflect.ValueOf(requireLinearHistoryProp)) && (ok || !reflect.DeepEqual(v, requireLinearHistoryProp)) { + obj["requireLinearHistory"] = requireLinearHistoryProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules?branch_rule_id={{branch_rule_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new BranchRule: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for BranchRule: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error creating BranchRule: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = SecureSourceManagerOperationWaitTime( + config, res, project, "Creating BranchRule", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create BranchRule: %s", err) + } + + log.Printf("[DEBUG] Finished creating BranchRule %q: %#v", d.Id(), res) + + return resourceSecureSourceManagerBranchRuleRead(d, meta) +} + +func resourceSecureSourceManagerBranchRuleRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for BranchRule: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("SecureSourceManagerBranchRule %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + + if err := d.Set("name", flattenSecureSourceManagerBranchRuleName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("uid", flattenSecureSourceManagerBranchRuleUid(res["uid"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("create_time", flattenSecureSourceManagerBranchRuleCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("update_time", flattenSecureSourceManagerBranchRuleUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("include_pattern", flattenSecureSourceManagerBranchRuleIncludePattern(res["includePattern"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("disabled", flattenSecureSourceManagerBranchRuleDisabled(res["disabled"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("require_pull_request", flattenSecureSourceManagerBranchRuleRequirePullRequest(res["requirePullRequest"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("minimum_reviews_count", flattenSecureSourceManagerBranchRuleMinimumReviewsCount(res["minimumReviewsCount"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("minimum_approvals_count", flattenSecureSourceManagerBranchRuleMinimumApprovalsCount(res["minimumApprovalsCount"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("require_comments_resolved", flattenSecureSourceManagerBranchRuleRequireCommentsResolved(res["requireCommentsResolved"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("allow_stale_reviews", flattenSecureSourceManagerBranchRuleAllowStaleReviews(res["allowStaleReviews"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + if err := d.Set("require_linear_history", flattenSecureSourceManagerBranchRuleRequireLinearHistory(res["requireLinearHistory"], d, config)); err != nil { + return fmt.Errorf("Error reading BranchRule: %s", err) + } + + return nil +} + +func resourceSecureSourceManagerBranchRuleUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for BranchRule: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + includePatternProp, err := expandSecureSourceManagerBranchRuleIncludePattern(d.Get("include_pattern"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("include_pattern"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, includePatternProp)) { + obj["includePattern"] = includePatternProp + } + disabledProp, err := expandSecureSourceManagerBranchRuleDisabled(d.Get("disabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("disabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, disabledProp)) { + obj["disabled"] = disabledProp + } + requirePullRequestProp, err := expandSecureSourceManagerBranchRuleRequirePullRequest(d.Get("require_pull_request"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("require_pull_request"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, requirePullRequestProp)) { + obj["requirePullRequest"] = requirePullRequestProp + } + minimumReviewsCountProp, err := expandSecureSourceManagerBranchRuleMinimumReviewsCount(d.Get("minimum_reviews_count"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("minimum_reviews_count"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, minimumReviewsCountProp)) { + obj["minimumReviewsCount"] = minimumReviewsCountProp + } + minimumApprovalsCountProp, err := expandSecureSourceManagerBranchRuleMinimumApprovalsCount(d.Get("minimum_approvals_count"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("minimum_approvals_count"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, minimumApprovalsCountProp)) { + obj["minimumApprovalsCount"] = minimumApprovalsCountProp + } + requireCommentsResolvedProp, err := expandSecureSourceManagerBranchRuleRequireCommentsResolved(d.Get("require_comments_resolved"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("require_comments_resolved"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, requireCommentsResolvedProp)) { + obj["requireCommentsResolved"] = requireCommentsResolvedProp + } + allowStaleReviewsProp, err := expandSecureSourceManagerBranchRuleAllowStaleReviews(d.Get("allow_stale_reviews"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("allow_stale_reviews"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, allowStaleReviewsProp)) { + obj["allowStaleReviews"] = allowStaleReviewsProp + } + requireLinearHistoryProp, err := expandSecureSourceManagerBranchRuleRequireLinearHistory(d.Get("require_linear_history"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("require_linear_history"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, requireLinearHistoryProp)) { + obj["requireLinearHistory"] = requireLinearHistoryProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating BranchRule %q: %#v", d.Id(), obj) + headers := make(http.Header) + updateMask := []string{} + + if d.HasChange("include_pattern") { + updateMask = append(updateMask, "includePattern") + } + + if d.HasChange("disabled") { + updateMask = append(updateMask, "disabled") + } + + if d.HasChange("require_pull_request") { + updateMask = append(updateMask, "requirePullRequest") + } + + if d.HasChange("minimum_reviews_count") { + updateMask = append(updateMask, "minimumReviewsCount") + } + + if d.HasChange("minimum_approvals_count") { + updateMask = append(updateMask, "minimumApprovalsCount") + } + + if d.HasChange("require_comments_resolved") { + updateMask = append(updateMask, "requireCommentsResolved") + } + + if d.HasChange("allow_stale_reviews") { + updateMask = append(updateMask, "allowStaleReviews") + } + + if d.HasChange("require_linear_history") { + updateMask = append(updateMask, "requireLinearHistory") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // if updateMask is empty we are not updating anything so skip the post + if len(updateMask) > 0 { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + Headers: headers, + }) + + if err != nil { + return fmt.Errorf("Error updating BranchRule %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating BranchRule %q: %#v", d.Id(), res) + } + + } + + return resourceSecureSourceManagerBranchRuleRead(d, meta) +} + +func resourceSecureSourceManagerBranchRuleDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for BranchRule: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + + log.Printf("[DEBUG] Deleting BranchRule %q", d.Id()) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "BranchRule") + } + + err = SecureSourceManagerOperationWaitTime( + config, res, project, "Deleting BranchRule", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting BranchRule %q: %#v", d.Id(), res) + return nil +} + +func resourceSecureSourceManagerBranchRuleImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/repositories/(?P[^/]+)/branchRules/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenSecureSourceManagerBranchRuleName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleUid(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleIncludePattern(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleDisabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleRequirePullRequest(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleMinimumReviewsCount(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenSecureSourceManagerBranchRuleMinimumApprovalsCount(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenSecureSourceManagerBranchRuleRequireCommentsResolved(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleAllowStaleReviews(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerBranchRuleRequireLinearHistory(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandSecureSourceManagerBranchRuleIncludePattern(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleDisabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleRequirePullRequest(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleMinimumReviewsCount(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleMinimumApprovalsCount(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleRequireCommentsResolved(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleAllowStaleReviews(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerBranchRuleRequireLinearHistory(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_generated_test.go b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_generated_test.go new file mode 100644 index 00000000000..db919b041a3 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_generated_test.go @@ -0,0 +1,190 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 securesourcemanager_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "prevent_destroy": false, + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckSecureSourceManagerBranchRuleDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleBasicExample(context), + }, + { + ResourceName: "google_secure_source_manager_branch_rule.basic", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"branch_rule_id", "location", "repository_id"}, + }, + }, + }) +} + +func testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-basic-instance%{random_suffix}" + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_repository" "repository" { + repository_id = "tf-test-my-basic-repository%{random_suffix}" + location = google_secure_source_manager_instance.instance.location + instance = google_secure_source_manager_instance.instance.name + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_branch_rule" "basic" { + branch_rule_id = "tf-test-my-basic-branchrule%{random_suffix}" + repository_id = google_secure_source_manager_repository.repository.repository_id + location = google_secure_source_manager_repository.repository.location + # This field is required for BranchRule creation + include_pattern = "main" +} +`, context) +} + +func TestAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "prevent_destroy": false, + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckSecureSourceManagerBranchRuleDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample(context), + }, + { + ResourceName: "google_secure_source_manager_branch_rule.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"branch_rule_id", "location", "repository_id"}, + }, + }, + }) +} + +func testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-initial-instance%{random_suffix}" + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_repository" "repository" { + repository_id = "tf-test-my-initial-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name + location = google_secure_source_manager_instance.instance.location + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_branch_rule" "default" { + branch_rule_id = "tf-test-my-initial-branchrule%{random_suffix}" + location = google_secure_source_manager_repository.repository.location + repository_id = google_secure_source_manager_repository.repository.repository_id + include_pattern = "test" + minimum_approvals_count = 2 + minimum_reviews_count = 2 + require_comments_resolved = true + require_linear_history = true + require_pull_request = true + disabled = false + allow_stale_reviews = false +} +`, context) +} + +func testAccCheckSecureSourceManagerBranchRuleDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_secure_source_manager_branch_rule" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("SecureSourceManagerBranchRule still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_sweeper.go b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_sweeper.go new file mode 100644 index 00000000000..2fed8329f93 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_sweeper.go @@ -0,0 +1,143 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 securesourcemanager + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("SecureSourceManagerBranchRule", testSweepSecureSourceManagerBranchRule) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepSecureSourceManagerBranchRule(region string) error { + resourceName := "SecureSourceManagerBranchRule" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://securesourcemanager.googleapis.com/v1/projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules?branch_rule_id={{branch_rule_id}}", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["branchRules"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + var name string + // Id detected in the delete URL, attempt to use id. + if obj["id"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["id"].(string)) + } else if obj["name"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + } else { + log.Printf("[INFO][SWEEPER_LOG] %s resource name and id were nil", resourceName) + return nil + } + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://securesourcemanager.googleapis.com/v1/projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_update_test.go b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_update_test.go new file mode 100644 index 00000000000..1b98ca9e5e0 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_branch_rule_update_test.go @@ -0,0 +1,114 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package securesourcemanager_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "prevent_destroy": false, + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample_full(context), + }, + { + ResourceName: "google_secure_source_manager_branch_rule.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"branch_rule_id", "location", "repository_id"}, + }, + { + Config: testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample_update(context), + }, + { + ResourceName: "google_secure_source_manager_branch_rule.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"branch_rule_id", "location", "repository_id"}, + }, + }, + }) +} + +func testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample_full(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-initial-instance%{random_suffix}" + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_repository" "repository" { + repository_id = "tf-test-my-initial-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name + location = google_secure_source_manager_instance.instance.location + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_branch_rule" "default" { + branch_rule_id = "tf-test-my-initial-branchrule%{random_suffix}" + location = google_secure_source_manager_repository.repository.location + repository_id = google_secure_source_manager_repository.repository.repository_id + include_pattern = "test" + minimum_approvals_count = 2 + minimum_reviews_count = 2 + require_comments_resolved = true + require_linear_history = true + require_pull_request = true + disabled = false + allow_stale_reviews = false +} +`, context) +} + +func testAccSecureSourceManagerBranchRule_secureSourceManagerBranchRuleWithFieldsExample_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-initial-instance%{random_suffix}" + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_repository" "repository" { + repository_id = "tf-test-my-initial-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name + location = google_secure_source_manager_instance.instance.location + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "%{prevent_destroy}" + } +} + +resource "google_secure_source_manager_branch_rule" "default" { + branch_rule_id = "tf-test-my-initial-branchrule%{random_suffix}" + location = google_secure_source_manager_repository.repository.location + repository_id = google_secure_source_manager_repository.repository.repository_id + include_pattern = "test" + minimum_approvals_count = 1 + minimum_reviews_count = 1 + require_linear_history = false +} +`, context) +} diff --git a/website/docs/r/secure_source_manager_branch_rule.html.markdown b/website/docs/r/secure_source_manager_branch_rule.html.markdown new file mode 100644 index 00000000000..cace63d615f --- /dev/null +++ b/website/docs/r/secure_source_manager_branch_rule.html.markdown @@ -0,0 +1,224 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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. +# +# ---------------------------------------------------------------------------- +subcategory: "Secure Source Manager" +description: |- + BranchRule is the protection rule to enforce pre-defined rules on designated branches within a repository. +--- + +# google_secure_source_manager_branch_rule + +BranchRule is the protection rule to enforce pre-defined rules on designated branches within a repository. + + +To get more information about BranchRule, see: +* How-to Guides + * [Official Documentation](https://cloud.google.com/secure-source-manager/docs/overview) + + +## Example Usage - Secure Source Manager Branch Rule Basic + + +```hcl +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "my-basic-instance" + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "true" + } +} + +resource "google_secure_source_manager_repository" "repository" { + repository_id = "my-basic-repository" + location = google_secure_source_manager_instance.instance.location + instance = google_secure_source_manager_instance.instance.name + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "true" + } +} + +resource "google_secure_source_manager_branch_rule" "basic" { + branch_rule_id = "my-basic-branchrule" + repository_id = google_secure_source_manager_repository.repository.repository_id + location = google_secure_source_manager_repository.repository.location + # This field is required for BranchRule creation + include_pattern = "main" +} +``` + +## Example Usage - Secure Source Manager Branch Rule With Fields + + +```hcl +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "my-initial-instance" + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "true" + } +} + +resource "google_secure_source_manager_repository" "repository" { + repository_id = "my-initial-repository" + instance = google_secure_source_manager_instance.instance.name + location = google_secure_source_manager_instance.instance.location + # Prevent accidental deletions. + lifecycle { + prevent_destroy = "true" + } +} + +resource "google_secure_source_manager_branch_rule" "default" { + branch_rule_id = "my-initial-branchrule" + location = google_secure_source_manager_repository.repository.location + repository_id = google_secure_source_manager_repository.repository.repository_id + include_pattern = "test" + minimum_approvals_count = 2 + minimum_reviews_count = 2 + require_comments_resolved = true + require_linear_history = true + require_pull_request = true + disabled = false + allow_stale_reviews = false +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `include_pattern` - + (Required) + The BranchRule matches branches based on the specified regular expression. Use .* to match all branches. + +* `branch_rule_id` - + (Required) + The ID for the BranchRule. + +* `location` - + (Required) + The location for the Repository. + +* `repository_id` - + (Required) + The ID for the Repository. + + +- - - + + +* `disabled` - + (Optional) + Determines if the branch rule is disabled or not. + +* `require_pull_request` - + (Optional) + Determines if the branch rule requires a pull request or not. + +* `minimum_reviews_count` - + (Optional) + The minimum number of reviews required for the branch rule to be matched. + +* `minimum_approvals_count` - + (Optional) + The minimum number of approvals required for the branch rule to be matched. + +* `require_comments_resolved` - + (Optional) + Determines if require comments resolved before merging to the branch. + +* `allow_stale_reviews` - + (Optional) + Determines if allow stale reviews or approvals before merging to the branch. + +* `require_linear_history` - + (Optional) + Determines if require linear history before merging to the branch. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}` + +* `name` - + The resource name for the BranchRule. + +* `uid` - + Unique identifier of the BranchRule. + +* `create_time` - + Time the BranchRule was created in UTC. + +* `update_time` - + Time the BranchRule was updated in UTC. + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +BranchRule can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}` +* `{{project}}/{{location}}/{{repository_id}}/{{branch_rule_id}}` +* `{{location}}/{{repository_id}}/{{branch_rule_id}}` +* `{{branch_rule_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import BranchRule using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}}" + to = google_secure_source_manager_branch_rule.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), BranchRule can be imported using one of the formats above. For example: + +``` +$ terraform import google_secure_source_manager_branch_rule.default projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/branchRules/{{branch_rule_id}} +$ terraform import google_secure_source_manager_branch_rule.default {{project}}/{{location}}/{{repository_id}}/{{branch_rule_id}} +$ terraform import google_secure_source_manager_branch_rule.default {{location}}/{{repository_id}}/{{branch_rule_id}} +$ terraform import google_secure_source_manager_branch_rule.default {{branch_rule_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).