diff --git a/mmv1/products/gemini/CodeRepositoryIndex.yaml b/mmv1/products/gemini/CodeRepositoryIndex.yaml index 62cb5236c845..c2730c35bfe6 100644 --- a/mmv1/products/gemini/CodeRepositoryIndex.yaml +++ b/mmv1/products/gemini/CodeRepositoryIndex.yaml @@ -51,9 +51,18 @@ async: result: resource_inside_response: true include_project: false +custom_code: + pre_delete: templates/terraform/pre_delete/code_repository_index_force_delete.go.tmpl error_retry_predicates: - 'transport_tpg.IsCodeRepositoryIndexUnreadyError' - 'transport_tpg.IsRepositoryGroupQueueError' +virtual_fields: + - name: 'force_destroy' + description: + If set to true, will allow deletion of the CodeRepositoryIndex even if there are existing + RepositoryGroups for the resource. These RepositoryGroups will also be deleted. + type: Boolean + default_value: false parameters: - name: location type: String diff --git a/mmv1/templates/terraform/pre_delete/code_repository_index_force_delete.go.tmpl b/mmv1/templates/terraform/pre_delete/code_repository_index_force_delete.go.tmpl new file mode 100644 index 000000000000..a451d1ece932 --- /dev/null +++ b/mmv1/templates/terraform/pre_delete/code_repository_index_force_delete.go.tmpl @@ -0,0 +1,8 @@ +{{- if ne $.TargetVersionName "ga" -}} +obj = make(map[string]interface{}) +if v, ok := d.GetOk("force_destroy"); ok { + if v == true { + obj["force"] = true + } +} +{{- end }} diff --git a/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl b/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl index ab1520dbc92b..ddbd7c17168f 100644 --- a/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl +++ b/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl @@ -2,6 +2,7 @@ package gemini_test {{- if ne $.TargetVersionName "ga" }} import ( + "fmt" "os" "testing" @@ -44,6 +45,136 @@ func TestAccGeminiCodeRepositoryIndex_update(t *testing.T) { }) } +// TestAccGeminiCodeRepositoryIndex_delete checks if there is no error in deleting CRI along with children resource +// note: this is an example of a bad usage, where RGs refer to the CRI using a string id, not a reference, as they +// will be force-removed upon CRI deletion, because the CRI provider uses --force option by default +// The plan after the _delete function should not be empty due to the child resource in plan +func TestAccGeminiCodeRepositoryIndex_delete(t *testing.T) { + bootstrappedKMS := acctest.BootstrapKMSKeyInLocation(t, "us-central1") + randomSuffix := acctest.RandString(t, 10) + context := map[string]interface{}{ + "random_suffix": randomSuffix, + "project_id": os.Getenv("GOOGLE_PROJECT"), + "kms_key": bootstrappedKMS.CryptoKey.Name, + "cri_id": fmt.Sprintf("tf-test-cri-index-delete-example-%s", randomSuffix), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccGeminiCodeRepositoryIndex_withChildren_basic(context), + }, + { + ResourceName: "google_gemini_code_repository_index.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"code_repository_index_id", "labels", "location", "terraform_labels", "force_destroy"}, + }, + { + Config: testAccGeminiCodeRepositoryIndex_withChildren_delete(context), + ExpectNonEmptyPlan: true, + PlanOnly: true, + }, + }, + }) +} + +func testAccGeminiCodeRepositoryIndex_withChildren_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_code_repository_index" "example" { + provider = google-beta + labels = {"ccfe_debug_note": "terraform_e2e_should_be_deleted"} + location = "us-central1" + code_repository_index_id = "%{cri_id}" + force_destroy = true +} + +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{cri_id}" + repository_group_id = "tf-test-rg-repository-group-id-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} + depends_on = [ + google_gemini_code_repository_index.example + ] +} + +resource "google_developer_connect_git_repository_link" "conn" { + provider = google-beta + git_repository_link_id = "tf-test-repository-conn-delete" + parent_connection = google_developer_connect_connection.github_conn.connection_id + clone_uri = "https://github.com/CC-R-github-robot/tf-test.git" + location = "us-central1" + annotations = {} +} + +resource "google_developer_connect_connection" "github_conn" { + provider = google-beta + location = "us-central1" + connection_id = "tf-test-cloudaicompanion-delete-%{random_suffix}" + disabled = false + + github_config { + github_app = "DEVELOPER_CONNECT" + app_installation_id = 54180648 + + authorizer_credential { + oauth_token_secret_version = "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1" + } + } +} +`, context) +} + +// Removed depends_on to not break plan test +func testAccGeminiCodeRepositoryIndex_withChildren_delete(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{cri_id}" + repository_group_id = "tf-test-rg-repository-group-id-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_developer_connect_git_repository_link" "conn" { + provider = google-beta + git_repository_link_id = "tf-test-repository-conn-delete" + parent_connection = google_developer_connect_connection.github_conn.connection_id + clone_uri = "https://github.com/CC-R-github-robot/tf-test.git" + location = "us-central1" + annotations = {} +} + +resource "google_developer_connect_connection" "github_conn" { + provider = google-beta + location = "us-central1" + connection_id = "tf-test-cloudaicompanion-delete-%{random_suffix}" + disabled = false + + github_config { + github_app = "DEVELOPER_CONNECT" + app_installation_id = 54180648 + + authorizer_credential { + oauth_token_secret_version = "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1" + } + } +} +`, context) +} + func testAccGeminiCodeRepositoryIndex_basic(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_gemini_code_repository_index" "example" {