agent-starter-pack 0.9.2__py3-none-any.whl → 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/METADATA +2 -2
  2. {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/RECORD +53 -51
  3. agents/adk_base/.template/templateconfig.yaml +1 -1
  4. agents/adk_gemini_fullstack/.template/templateconfig.yaml +1 -1
  5. agents/agentic_rag/.template/templateconfig.yaml +1 -1
  6. agents/agentic_rag/README.md +1 -1
  7. agents/live_api/tests/integration/test_server_e2e.py +7 -1
  8. llm.txt +3 -2
  9. src/base_template/Makefile +4 -3
  10. src/base_template/README.md +7 -2
  11. src/base_template/deployment/README.md +6 -121
  12. src/base_template/deployment/terraform/github.tf +284 -0
  13. src/base_template/deployment/terraform/providers.tf +5 -0
  14. src/base_template/deployment/terraform/variables.tf +40 -1
  15. src/base_template/deployment/terraform/vars/env.tfvars +7 -1
  16. src/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
  17. src/base_template/deployment/terraform/{build_triggers.tf → {% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} } +33 -18
  18. src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +114 -0
  19. src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
  20. src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +170 -0
  21. src/base_template/{deployment/cd/deploy-to-prod.yaml → {% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml } +7 -7
  22. src/base_template/{deployment/cd/staging.yaml → {% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml } +7 -7
  23. src/cli/commands/create.py +120 -4
  24. src/cli/commands/list.py +1 -1
  25. src/cli/commands/setup_cicd.py +292 -298
  26. src/cli/utils/cicd.py +19 -7
  27. src/cli/utils/remote_template.py +4 -4
  28. src/cli/utils/template.py +67 -19
  29. src/deployment_targets/cloud_run/app/server.py +19 -0
  30. src/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +4 -3
  31. src/deployment_targets/cloud_run/deployment/terraform/service.tf +4 -3
  32. src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +35 -0
  33. src/deployment_targets/cloud_run/tests/load_test/README.md +1 -1
  34. src/frontends/live_api_react/frontend/package-lock.json +19 -16
  35. src/frontends/streamlit/frontend/side_bar.py +1 -1
  36. src/frontends/streamlit/frontend/utils/chat_utils.py +1 -1
  37. src/frontends/streamlit/frontend/utils/local_chat_history.py +2 -2
  38. src/resources/docs/adk-cheatsheet.md +1 -1
  39. src/resources/locks/uv-adk_base-agent_engine.lock +164 -131
  40. src/resources/locks/uv-adk_base-cloud_run.lock +177 -144
  41. src/resources/locks/uv-adk_gemini_fullstack-agent_engine.lock +164 -131
  42. src/resources/locks/uv-adk_gemini_fullstack-cloud_run.lock +177 -144
  43. src/resources/locks/uv-agentic_rag-agent_engine.lock +223 -190
  44. src/resources/locks/uv-agentic_rag-cloud_run.lock +251 -218
  45. src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +315 -485
  46. src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +358 -531
  47. src/resources/locks/uv-langgraph_base_react-agent_engine.lock +281 -249
  48. src/resources/locks/uv-langgraph_base_react-cloud_run.lock +323 -290
  49. src/resources/locks/uv-live_api-cloud_run.lock +350 -327
  50. src/resources/setup_cicd/cicd_variables.tf +0 -41
  51. src/resources/setup_cicd/github.tf +0 -87
  52. src/resources/setup_cicd/providers.tf +0 -39
  53. {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/WHEEL +0 -0
  54. {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/entry_points.txt +0 -0
  55. {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/licenses/LICENSE +0 -0
  56. /src/base_template/{deployment/ci → {% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}}/pr_checks.yaml +0 -0
@@ -0,0 +1,284 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ provider "github" {
16
+ owner = var.repository_owner
17
+ }
18
+
19
+ # Try to get existing repo
20
+ data "github_repository" "existing_repo" {
21
+ count = var.create_repository ? 0 : 1
22
+ full_name = "${var.repository_owner}/${var.repository_name}"
23
+ }
24
+
25
+ # Only create GitHub repo if create_repository is true
26
+ resource "github_repository" "repo" {
27
+ count = var.create_repository ? 1 : 0
28
+ name = var.repository_name
29
+ description = "Repository created with goo.gle/agent-starter-pack"
30
+ visibility = "private"
31
+
32
+ has_issues = true
33
+ has_wiki = false
34
+ has_projects = false
35
+ has_downloads = false
36
+
37
+ allow_merge_commit = true
38
+ allow_squash_merge = true
39
+ allow_rebase_merge = true
40
+
41
+ auto_init = false
42
+ }
43
+
44
+ {% if cookiecutter.cicd_runner == 'github_actions' %}
45
+ resource "github_actions_variable" "gcp_project_number" {
46
+ repository = var.repository_name
47
+ variable_name = "GCP_PROJECT_NUMBER"
48
+ value = data.google_project.cicd_project.number
49
+ depends_on = [github_repository.repo]
50
+ }
51
+
52
+ resource "github_actions_secret" "wif_pool_id" {
53
+ repository = var.repository_name
54
+ secret_name = "WIF_POOL_ID"
55
+ plaintext_value = google_iam_workload_identity_pool.github_pool.workload_identity_pool_id
56
+ depends_on = [github_repository.repo, data.github_repository.existing_repo]
57
+ }
58
+
59
+ resource "github_actions_secret" "wif_provider_id" {
60
+ repository = var.repository_name
61
+ secret_name = "WIF_PROVIDER_ID"
62
+ plaintext_value = google_iam_workload_identity_pool_provider.github_provider.workload_identity_pool_provider_id
63
+ depends_on = [github_repository.repo, data.github_repository.existing_repo]
64
+ }
65
+
66
+ resource "github_actions_secret" "gcp_service_account" {
67
+ repository = var.repository_name
68
+ secret_name = "GCP_SERVICE_ACCOUNT"
69
+ plaintext_value = google_service_account.cicd_runner_sa.email
70
+ depends_on = [github_repository.repo, data.github_repository.existing_repo]
71
+ }
72
+
73
+ resource "github_actions_variable" "staging_project_id" {
74
+ repository = var.repository_name
75
+ variable_name = "STAGING_PROJECT_ID"
76
+ value = var.staging_project_id
77
+ depends_on = [github_repository.repo]
78
+ }
79
+
80
+ resource "github_actions_variable" "prod_project_id" {
81
+ repository = var.repository_name
82
+ variable_name = "PROD_PROJECT_ID"
83
+ value = var.prod_project_id
84
+ depends_on = [github_repository.repo]
85
+ }
86
+
87
+ resource "github_actions_variable" "region" {
88
+ repository = var.repository_name
89
+ variable_name = "REGION"
90
+ value = var.region
91
+ depends_on = [github_repository.repo]
92
+ }
93
+
94
+ resource "github_actions_variable" "cicd_project_id" {
95
+ repository = var.repository_name
96
+ variable_name = "CICD_PROJECT_ID"
97
+ value = var.cicd_runner_project_id
98
+ depends_on = [github_repository.repo]
99
+ }
100
+
101
+ resource "github_actions_variable" "bucket_name_load_test_results" {
102
+ repository = var.repository_name
103
+ variable_name = "BUCKET_NAME_LOAD_TEST_RESULTS"
104
+ value = google_storage_bucket.bucket_load_test_results.name
105
+ depends_on = [github_repository.repo]
106
+ }
107
+
108
+ {% if cookiecutter.deployment_target == 'cloud_run' %}
109
+ resource "github_actions_variable" "container_name" {
110
+ repository = var.repository_name
111
+ variable_name = "CONTAINER_NAME"
112
+ value = var.project_name
113
+ depends_on = [github_repository.repo]
114
+ }
115
+
116
+ resource "github_actions_variable" "artifact_registry_repo_name" {
117
+ repository = var.repository_name
118
+ variable_name = "ARTIFACT_REGISTRY_REPO_NAME"
119
+ value = google_artifact_registry_repository.repo-artifacts-genai.repository_id
120
+ depends_on = [github_repository.repo]
121
+ }
122
+ {% endif %}
123
+
124
+ {% if cookiecutter.data_ingestion %}
125
+ resource "github_actions_variable" "pipeline_gcs_root_staging" {
126
+ repository = var.repository_name
127
+ variable_name = "PIPELINE_GCS_ROOT_STAGING"
128
+ value = "gs://${google_storage_bucket.data_ingestion_pipeline_gcs_root["staging"].name}"
129
+ depends_on = [github_repository.repo]
130
+ }
131
+
132
+ resource "github_actions_variable" "pipeline_gcs_root_prod" {
133
+ repository = var.repository_name
134
+ variable_name = "PIPELINE_GCS_ROOT_PROD"
135
+ value = "gs://${google_storage_bucket.data_ingestion_pipeline_gcs_root["prod"].name}"
136
+ depends_on = [github_repository.repo]
137
+ }
138
+
139
+ resource "github_actions_variable" "pipeline_sa_email_staging" {
140
+ repository = var.repository_name
141
+ variable_name = "PIPELINE_SA_EMAIL_STAGING"
142
+ value = google_service_account.vertexai_pipeline_app_sa["staging"].email
143
+ depends_on = [github_repository.repo]
144
+ }
145
+
146
+ resource "github_actions_variable" "pipeline_sa_email_prod" {
147
+ repository = var.repository_name
148
+ variable_name = "PIPELINE_SA_EMAIL_PROD"
149
+ value = google_service_account.vertexai_pipeline_app_sa["prod"].email
150
+ depends_on = [github_repository.repo]
151
+ }
152
+
153
+ resource "github_actions_variable" "pipeline_name" {
154
+ repository = var.repository_name
155
+ variable_name = "PIPELINE_NAME"
156
+ value = var.project_name
157
+ depends_on = [github_repository.repo]
158
+ }
159
+
160
+ resource "github_actions_variable" "pipeline_cron_schedule" {
161
+ repository = var.repository_name
162
+ variable_name = "PIPELINE_CRON_SCHEDULE"
163
+ value = var.pipeline_cron_schedule
164
+ depends_on = [github_repository.repo]
165
+ }
166
+
167
+ {% if cookiecutter.datastore_type == "vertex_ai_search" %}
168
+ resource "github_actions_variable" "data_store_id_staging" {
169
+ repository = var.repository_name
170
+ variable_name = "DATA_STORE_ID_STAGING"
171
+ value = google_discovery_engine_data_store.data_store_staging.data_store_id
172
+ depends_on = [github_repository.repo]
173
+ }
174
+
175
+ resource "github_actions_variable" "data_store_id_prod" {
176
+ repository = var.repository_name
177
+ variable_name = "DATA_STORE_ID_PROD"
178
+ value = google_discovery_engine_data_store.data_store_prod.data_store_id
179
+ depends_on = [github_repository.repo]
180
+ }
181
+
182
+ resource "github_actions_variable" "data_store_region" {
183
+ repository = var.repository_name
184
+ variable_name = "DATA_STORE_REGION"
185
+ value = var.data_store_region
186
+ depends_on = [github_repository.repo]
187
+ }
188
+ {% elif cookiecutter.datastore_type == "vertex_ai_vector_search" %}
189
+ resource "github_actions_variable" "vector_search_index_staging" {
190
+ repository = var.repository_name
191
+ variable_name = "VECTOR_SEARCH_INDEX_STAGING"
192
+ value = google_vertex_ai_index.vector_search_index_staging.id
193
+ depends_on = [github_repository.repo]
194
+ }
195
+
196
+ resource "github_actions_variable" "vector_search_index_prod" {
197
+ repository = var.repository_name
198
+ variable_name = "VECTOR_SEARCH_INDEX_PROD"
199
+ value = google_vertex_ai_index.vector_search_index_prod.id
200
+ depends_on = [github_repository.repo]
201
+ }
202
+
203
+ resource "github_actions_variable" "vector_search_index_endpoint_staging" {
204
+ repository = var.repository_name
205
+ variable_name = "VECTOR_SEARCH_INDEX_ENDPOINT_STAGING"
206
+ value = google_vertex_ai_index_endpoint.vector_search_index_endpoint_staging.id
207
+ depends_on = [github_repository.repo]
208
+ }
209
+
210
+ resource "github_actions_variable" "vector_search_index_endpoint_prod" {
211
+ repository = var.repository_name
212
+ variable_name = "VECTOR_SEARCH_INDEX_ENDPOINT_PROD"
213
+ value = google_vertex_ai_index_endpoint.vector_search_index_endpoint_prod.id
214
+ depends_on = [github_repository.repo]
215
+ }
216
+
217
+ resource "github_actions_variable" "vector_search_bucket_staging" {
218
+ repository = var.repository_name
219
+ variable_name = "VECTOR_SEARCH_BUCKET_STAGING"
220
+ value = google_storage_bucket.vector_search_data_bucket["staging"].url
221
+ depends_on = [github_repository.repo]
222
+ }
223
+
224
+ resource "github_actions_variable" "vector_search_bucket_prod" {
225
+ repository = var.repository_name
226
+ variable_name = "VECTOR_SEARCH_BUCKET_PROD"
227
+ value = google_storage_bucket.vector_search_data_bucket["prod"].url
228
+ depends_on = [github_repository.repo]
229
+ }
230
+ {% endif %}
231
+ {% endif %}
232
+
233
+ resource "github_repository_environment" "production_environment" {
234
+ repository = var.repository_name
235
+ environment = "production"
236
+ depends_on = [github_repository.repo, data.github_repository.existing_repo]
237
+
238
+ deployment_branch_policy {
239
+ protected_branches = false
240
+ custom_branch_policies = true
241
+ }
242
+ }
243
+ {% else %}
244
+
245
+ # Reference existing GitHub PAT secret created by gcloud CLI
246
+ data "google_secret_manager_secret" "github_pat" {
247
+ project = var.cicd_runner_project_id
248
+ secret_id = var.github_pat_secret_id
249
+ }
250
+
251
+ # Create the GitHub connection (fallback for manual Terraform usage)
252
+ resource "google_cloudbuildv2_connection" "github_connection" {
253
+ count = var.create_cb_connection ? 0 : 1
254
+ project = var.cicd_runner_project_id
255
+ location = var.region
256
+ name = var.host_connection_name
257
+
258
+ github_config {
259
+ app_installation_id = var.github_app_installation_id
260
+ authorizer_credential {
261
+ oauth_token_secret_version = "${data.google_secret_manager_secret.github_pat.id}/versions/latest"
262
+ }
263
+ }
264
+ depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
265
+ }
266
+
267
+
268
+ resource "google_cloudbuildv2_repository" "repo" {
269
+ project = var.cicd_runner_project_id
270
+ location = var.region
271
+ name = var.repository_name
272
+
273
+ # Use existing connection ID when it exists, otherwise use the created connection
274
+ parent_connection = var.create_cb_connection ? "projects/${var.cicd_runner_project_id}/locations/${var.region}/connections/${var.host_connection_name}" : google_cloudbuildv2_connection.github_connection[0].id
275
+ remote_uri = "https://github.com/${var.repository_owner}/${var.repository_name}.git"
276
+ depends_on = [
277
+ resource.google_project_service.cicd_services,
278
+ resource.google_project_service.deploy_project_services,
279
+ data.github_repository.existing_repo,
280
+ github_repository.repo,
281
+ google_cloudbuildv2_connection.github_connection,
282
+ ]
283
+ }
284
+ {% endif %}
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+
15
16
  terraform {
16
17
  required_version = ">= 1.0.0"
17
18
  required_providers {
@@ -19,6 +20,10 @@ terraform {
19
20
  source = "hashicorp/google"
20
21
  version = "< 7.0.0"
21
22
  }
23
+ github = {
24
+ source = "integrations/github"
25
+ version = "~> 6.5.0"
26
+ }
22
27
  }
23
28
  }
24
29
 
@@ -40,8 +40,9 @@ variable "region" {
40
40
  }
41
41
 
42
42
  variable "host_connection_name" {
43
- description = "Name of the host connection you created in Cloud Build"
43
+ description = "Name of the host connection to create in Cloud Build"
44
44
  type = string
45
+ default = "{{ cookiecutter.project_name }}-github-connection"
45
46
  }
46
47
 
47
48
  variable "repository_name" {
@@ -186,3 +187,41 @@ variable "vector_search_machine_type" {
186
187
  }
187
188
  {% endif %}
188
189
  {% endif %}
190
+ variable "repository_owner" {
191
+ description = "Owner of the Git repository - username or organization"
192
+ type = string
193
+ }
194
+ {% if cookiecutter.cicd_runner == "github_actions" %}
195
+
196
+
197
+ variable "create_repository" {
198
+ description = "Flag indicating whether to create a new Git repository"
199
+ type = bool
200
+ default = false
201
+ }
202
+ {% else %}
203
+ variable "github_app_installation_id" {
204
+ description = "GitHub App Installation ID for Cloud Build"
205
+ type = string
206
+ default = null
207
+ }
208
+
209
+
210
+ variable "github_pat_secret_id" {
211
+ description = "GitHub PAT Secret ID created by gcloud CLI"
212
+ type = string
213
+ default = null
214
+ }
215
+
216
+ variable "create_cb_connection" {
217
+ description = "Flag indicating if a Cloud Build connection already exists"
218
+ type = bool
219
+ default = false
220
+ }
221
+
222
+ variable "create_repository" {
223
+ description = "Flag indicating whether to create a new Git repository"
224
+ type = bool
225
+ default = false
226
+ }
227
+ {% endif %}
@@ -10,11 +10,13 @@ staging_project_id = "your-staging-project-id"
10
10
  # Your Google Cloud project ID that will be used to host the Cloud Build pipelines.
11
11
  cicd_runner_project_id = "your-cicd-project-id"
12
12
 
13
+ {%- if cookiecutter.cicd_runner == "google_cloud_build" %}
13
14
  # Name of the host connection you created in Cloud Build
14
15
  host_connection_name = "git-{{cookiecutter.project_name}}"
16
+ {%- endif %}
15
17
 
16
18
  # Name of the repository you added to Cloud Build
17
- repository_name = "repo-{{cookiecutter.project_name}}"
19
+ repository_name = "{{cookiecutter.project_name}}"
18
20
 
19
21
  # The Google Cloud region you will use to deploy the infrastructure
20
22
  region = "us-central1"
@@ -32,3 +34,7 @@ vector_search_min_replica_count = 1
32
34
  vector_search_max_replica_count = 1
33
35
  {%- endif %}
34
36
  {%- endif %}
37
+ {%- if cookiecutter.cicd_runner == "github_actions" %}
38
+
39
+ repository_owner = "Your GitHub organization or username."
40
+ {%- endif %}
@@ -0,0 +1,43 @@
1
+
2
+ data "google_project" "cicd_project" {
3
+ project_id = var.cicd_runner_project_id
4
+ }
5
+
6
+ resource "google_service_account_iam_member" "github_oidc_access" {
7
+ service_account_id = resource.google_service_account.cicd_runner_sa.name
8
+ role = "roles/iam.workloadIdentityUser"
9
+ member = "principalSet://iam.googleapis.com/projects/${data.google_project.cicd_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.github_pool.workload_identity_pool_id}/attribute.repository/${var.repository_owner}/${var.repository_name}"
10
+ depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
11
+ }
12
+
13
+ # Allow the GitHub Actions principal to impersonate the CICD runner service account
14
+ resource "google_service_account_iam_member" "github_sa_impersonation" {
15
+ service_account_id = resource.google_service_account.cicd_runner_sa.name
16
+ role = "roles/iam.serviceAccountTokenCreator"
17
+ member = "principalSet://iam.googleapis.com/projects/${data.google_project.cicd_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.github_pool.workload_identity_pool_id}/attribute.repository/${var.repository_owner}/${var.repository_name}"
18
+ depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
19
+ }
20
+
21
+ resource "google_iam_workload_identity_pool" "github_pool" {
22
+ workload_identity_pool_id = "${var.project_name}-pool"
23
+ project = var.cicd_runner_project_id
24
+ display_name = "GitHub Actions Pool"
25
+ depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
26
+ }
27
+
28
+ resource "google_iam_workload_identity_pool_provider" "github_provider" {
29
+ workload_identity_pool_provider_id = "${var.project_name}-oidc"
30
+ project = var.cicd_runner_project_id
31
+ workload_identity_pool_id = google_iam_workload_identity_pool.github_pool.workload_identity_pool_id
32
+ display_name = "GitHub OIDC Provider"
33
+ oidc {
34
+ issuer_uri = "https://token.actions.githubusercontent.com"
35
+ }
36
+ attribute_mapping = {
37
+ "google.subject" = "assertion.sub"
38
+ "attribute.repository" = "assertion.repository"
39
+ "attribute.repository_owner" = "assertion.repository_owner"
40
+ }
41
+ attribute_condition = "attribute.repository == '${var.repository_owner}/${var.repository_name}'"
42
+ depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
43
+ }
@@ -27,7 +27,7 @@ resource "google_cloudbuild_trigger" "pr_checks" {
27
27
  }
28
28
  }
29
29
 
30
- filename = "deployment/ci/pr_checks.yaml"
30
+ filename = ".cloudbuild/pr_checks.yaml"
31
31
  included_files = [
32
32
  "app/**",
33
33
  "data_ingestion/**",
@@ -39,7 +39,12 @@ resource "google_cloudbuild_trigger" "pr_checks" {
39
39
  {% endif %}
40
40
  ]
41
41
  include_build_logs = "INCLUDE_BUILD_LOGS_WITH_STATUS"
42
- depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
42
+ depends_on = [
43
+ resource.google_project_service.cicd_services,
44
+ resource.google_project_service.deploy_project_services,
45
+ google_cloudbuildv2_connection.github_connection,
46
+ google_cloudbuildv2_repository.repo
47
+ ]
43
48
  }
44
49
 
45
50
  # b. Create CD pipeline trigger
@@ -57,7 +62,7 @@ resource "google_cloudbuild_trigger" "cd_pipeline" {
57
62
  }
58
63
  }
59
64
 
60
- filename = "deployment/cd/staging.yaml"
65
+ filename = ".cloudbuild/staging.yaml"
61
66
  included_files = [
62
67
  "app/**",
63
68
  "data_ingestion/**",
@@ -76,22 +81,27 @@ resource "google_cloudbuild_trigger" "cd_pipeline" {
76
81
  _CLOUD_RUN_APP_SA_EMAIL = resource.google_service_account.cloud_run_app_sa["staging"].email
77
82
  {% endif %}
78
83
  {% if cookiecutter.data_ingestion %}
79
- _PIPELINE_GCS_ROOT = "gs://${resource.google_storage_bucket.data_ingestion_pipeline_gcs_root["staging"].name}"
80
- _PIPELINE_SA_EMAIL = resource.google_service_account.vertexai_pipeline_app_sa["staging"].email
84
+ _PIPELINE_GCS_ROOT_STAGING = "gs://${resource.google_storage_bucket.data_ingestion_pipeline_gcs_root["staging"].name}"
85
+ _PIPELINE_SA_EMAIL_STAGING = resource.google_service_account.vertexai_pipeline_app_sa["staging"].email
81
86
  _PIPELINE_CRON_SCHEDULE = var.pipeline_cron_schedule
82
87
  {% if cookiecutter.datastore_type == "vertex_ai_search" %}
83
- _DATA_STORE_ID = resource.google_discovery_engine_data_store.data_store_staging.data_store_id
88
+ _DATA_STORE_ID_STAGING = resource.google_discovery_engine_data_store.data_store_staging.data_store_id
84
89
  _DATA_STORE_REGION = var.data_store_region
85
90
  {% elif cookiecutter.datastore_type == "vertex_ai_vector_search" %}
86
- _VECTOR_SEARCH_INDEX = resource.google_vertex_ai_index.vector_search_index_staging.id
87
- _VECTOR_SEARCH_INDEX_ENDPOINT = resource.google_vertex_ai_index_endpoint.vector_search_index_endpoint_staging.id
88
- _VECTOR_SEARCH_BUCKET = resource.google_storage_bucket.vector_search_data_bucket["staging"].url
91
+ _VECTOR_SEARCH_INDEX_STAGING = resource.google_vertex_ai_index.vector_search_index_staging.id
92
+ _VECTOR_SEARCH_INDEX_ENDPOINT_STAGING = resource.google_vertex_ai_index_endpoint.vector_search_index_endpoint_staging.id
93
+ _VECTOR_SEARCH_BUCKET_STAGING = resource.google_storage_bucket.vector_search_data_bucket["staging"].url
89
94
 
90
95
  {% endif %}
91
96
  {% endif %}
92
97
  # Your other CD Pipeline substitutions
93
98
  }
94
- depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
99
+ depends_on = [
100
+ resource.google_project_service.cicd_services,
101
+ resource.google_project_service.deploy_project_services,
102
+ google_cloudbuildv2_connection.github_connection,
103
+ google_cloudbuildv2_repository.repo
104
+ ]
95
105
 
96
106
  }
97
107
 
@@ -105,7 +115,7 @@ resource "google_cloudbuild_trigger" "deploy_to_prod_pipeline" {
105
115
  repository_event_config {
106
116
  repository = "projects/${var.cicd_runner_project_id}/locations/${var.region}/connections/${var.host_connection_name}/repositories/${var.repository_name}"
107
117
  }
108
- filename = "deployment/cd/deploy-to-prod.yaml"
118
+ filename = ".cloudbuild/deploy-to-prod.yaml"
109
119
  include_build_logs = "INCLUDE_BUILD_LOGS_WITH_STATUS"
110
120
  approval_config {
111
121
  approval_required = true
@@ -119,20 +129,25 @@ resource "google_cloudbuild_trigger" "deploy_to_prod_pipeline" {
119
129
  _CLOUD_RUN_APP_SA_EMAIL = resource.google_service_account.cloud_run_app_sa["prod"].email
120
130
  {% endif %}
121
131
  {% if cookiecutter.data_ingestion %}
122
- _PIPELINE_GCS_ROOT = "gs://${resource.google_storage_bucket.data_ingestion_pipeline_gcs_root["prod"].name}"
123
- _PIPELINE_SA_EMAIL = resource.google_service_account.vertexai_pipeline_app_sa["prod"].email
132
+ _PIPELINE_GCS_ROOT_PROD = "gs://${resource.google_storage_bucket.data_ingestion_pipeline_gcs_root["prod"].name}"
133
+ _PIPELINE_SA_EMAIL_PROD = resource.google_service_account.vertexai_pipeline_app_sa["prod"].email
124
134
  _PIPELINE_CRON_SCHEDULE = var.pipeline_cron_schedule
125
135
  {% if cookiecutter.datastore_type == "vertex_ai_search" %}
126
- _DATA_STORE_ID = resource.google_discovery_engine_data_store.data_store_prod.data_store_id
136
+ _DATA_STORE_ID_PROD = resource.google_discovery_engine_data_store.data_store_prod.data_store_id
127
137
  _DATA_STORE_REGION = var.data_store_region
128
138
  {% elif cookiecutter.datastore_type == "vertex_ai_vector_search" %}
129
- _VECTOR_SEARCH_INDEX = resource.google_vertex_ai_index.vector_search_index_prod.id
130
- _VECTOR_SEARCH_INDEX_ENDPOINT = resource.google_vertex_ai_index_endpoint.vector_search_index_endpoint_prod.id
131
- _VECTOR_SEARCH_BUCKET = resource.google_storage_bucket.vector_search_data_bucket["prod"].url
139
+ _VECTOR_SEARCH_INDEX_PROD = resource.google_vertex_ai_index.vector_search_index_prod.id
140
+ _VECTOR_SEARCH_INDEX_ENDPOINT_PROD = resource.google_vertex_ai_index_endpoint.vector_search_index_endpoint_prod.id
141
+ _VECTOR_SEARCH_BUCKET_PROD = resource.google_storage_bucket.vector_search_data_bucket["prod"].url
132
142
  {% endif %}
133
143
  {% endif %}
134
144
  # Your other Deploy to Prod Pipeline substitutions
135
145
  }
136
- depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
146
+ depends_on = [
147
+ resource.google_project_service.cicd_services,
148
+ resource.google_project_service.deploy_project_services,
149
+ google_cloudbuildv2_connection.github_connection,
150
+ google_cloudbuildv2_repository.repo
151
+ ]
137
152
 
138
153
  }
@@ -0,0 +1,114 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ name: Deploy to Production
16
+
17
+ on:
18
+ workflow_dispatch:
19
+ workflow_call:
20
+
21
+ jobs:
22
+ deploy:
23
+ runs-on: ubuntu-latest
24
+ # This job targets the 'production' environment, which is automatically
25
+ # created by the Terraform setup in `deployment/terraform/github.tf`.
26
+ # To enable manual approval for deployments, you must add a protection
27
+ # rule to this environment in your GitHub repository settings.
28
+ #
29
+ # 1. Go to your repository's Settings > Environments.
30
+ # 2. Select the 'production' environment.
31
+ # 3. Under 'Protection rules', check the 'Required reviewers' box.
32
+ # 4. Add the specific users or teams who must approve the deployment.
33
+ #
34
+ # Once configured, the workflow will pause at this step and wait for an
35
+ # authorized user to approve it before proceeding.
36
+ environment:
37
+ name: production
38
+ concurrency: production
39
+ permissions:
40
+ contents: 'read'
41
+ id-token: 'write'
42
+
43
+ steps:
44
+ - name: Checkout code
45
+ uses: actions/checkout@v4
46
+
47
+ - name: Set up Python 3.11
48
+ uses: actions/setup-python@v4
49
+ with:
50
+ python-version: '3.11'
51
+
52
+ - id: 'auth'
53
+ name: 'Authenticate to Google Cloud'
54
+ uses: 'google-github-actions/auth@v2'
55
+ with:
56
+ workload_identity_provider: 'projects/{% raw %}${{ vars.GCP_PROJECT_NUMBER }}{% endraw %}/locations/global/workloadIdentityPools/{% raw %}${{ secrets.WIF_POOL_ID }}{% endraw %}/providers/{% raw %}${{ secrets.WIF_PROVIDER_ID }}{% endraw %}'
57
+ service_account: '{% raw %}${{ secrets.GCP_SERVICE_ACCOUNT }}{% endraw %}'
58
+ create_credentials_file: true
59
+ project_id: {% raw %}${{ vars.CICD_PROJECT_ID }}{% endraw %}
60
+
61
+ {%- if cookiecutter.deployment_target == 'cloud_run' %}
62
+
63
+ - name: Set up Cloud SDK
64
+ uses: 'google-github-actions/setup-gcloud@v2'
65
+ {%- endif %}
66
+
67
+ - name: Install uv and dependencies
68
+ run: |
69
+ pip install uv==0.6.12
70
+ uv sync --locked
71
+
72
+ {%- if cookiecutter.data_ingestion %}
73
+ - name: Deploy data ingestion pipeline (Production)
74
+ run: |
75
+ cd data_ingestion && pip install uv==0.6.12 && cd data_ingestion_pipeline && \
76
+ uv sync --locked && uv run python submit_pipeline.py
77
+ env:
78
+ PIPELINE_ROOT: {% raw %}${{ vars.PIPELINE_GCS_ROOT_PROD }}{% endraw %}
79
+ REGION: {% raw %}${{ vars.REGION }}{% endraw %}
80
+ {%- if cookiecutter.datastore_type == "vertex_ai_search" %}
81
+ DATA_STORE_REGION: {% raw %}${{ vars.DATA_STORE_REGION }}{% endraw %}
82
+ DATA_STORE_ID: {% raw %}${{ vars.DATA_STORE_ID_PROD }}{% endraw %}
83
+ {%- elif cookiecutter.datastore_type == "vertex_ai_vector_search" %}
84
+ VECTOR_SEARCH_INDEX: {% raw %}${{ vars.VECTOR_SEARCH_INDEX_PROD }}{% endraw %}
85
+ VECTOR_SEARCH_INDEX_ENDPOINT: {% raw %}${{ vars.VECTOR_SEARCH_INDEX_ENDPOINT_PROD }}{% endraw %}
86
+ VECTOR_SEARCH_BUCKET: {% raw %}${{ vars.VECTOR_SEARCH_BUCKET_PROD }}{% endraw %}
87
+ {%- endif %}
88
+ PROJECT_ID: {% raw %}${{ vars.PROD_PROJECT_ID }}{% endraw %}
89
+ SERVICE_ACCOUNT: {% raw %}${{ vars.PIPELINE_SA_EMAIL_PROD }}{% endraw %}
90
+ PIPELINE_NAME: {% raw %}${{ vars.PIPELINE_NAME }}{% endraw %}
91
+ CRON_SCHEDULE: {% raw %}${{ vars.PIPELINE_CRON_SCHEDULE }}{% endraw %}
92
+ DISABLE_CACHING: "TRUE"
93
+ {%- endif %}
94
+
95
+ {%- if cookiecutter.deployment_target == 'cloud_run' %}
96
+
97
+ - name: Deploy to Production (Cloud Run)
98
+ run: |
99
+ gcloud run deploy {{cookiecutter.project_name}} \
100
+ --image {% raw %}${{ vars.REGION }}{% endraw %}-docker.pkg.dev/{% raw %}${{ vars.CICD_PROJECT_ID }}{% endraw %}/{% raw %}${{ vars.ARTIFACT_REGISTRY_REPO_NAME }}{% endraw %}/{% raw %}${{ vars.CONTAINER_NAME }}{% endraw %} \
101
+ --region {% raw %}${{ vars.REGION }}{% endraw %} \
102
+ --project {% raw %}${{ vars.PROD_PROJECT_ID }}{% endraw %}
103
+
104
+ {%- elif cookiecutter.deployment_target == 'agent_engine' %}
105
+
106
+ - name: Deploy to Production (Agent Engine)
107
+ run: |
108
+ uv export --no-hashes --no-sources --no-header --no-dev --no-emit-project --no-annotate --locked > .requirements.txt
109
+ uv run app/agent_engine_app.py \
110
+ --project {% raw %}${{ vars.PROD_PROJECT_ID }}{% endraw %} \
111
+ --location {% raw %}${{ vars.REGION }}{% endraw %} \
112
+ --set-env-vars="COMMIT_SHA={% raw %}${{ github.sha }}{% endraw %}{%- if cookiecutter.data_ingestion %}{%- if cookiecutter.datastore_type == "vertex_ai_search" %},DATA_STORE_ID={% raw %}${{ vars.DATA_STORE_ID_PROD }}{% endraw %},DATA_STORE_REGION={% raw %}${{ vars.DATA_STORE_REGION }}{% endraw %}{%- elif cookiecutter.datastore_type == "vertex_ai_vector_search" %},VECTOR_SEARCH_INDEX={% raw %}${{ vars.VECTOR_SEARCH_INDEX_PROD }}{% endraw %},VECTOR_SEARCH_INDEX_ENDPOINT={% raw %}${{ vars.VECTOR_SEARCH_INDEX_ENDPOINT_PROD }}{% endraw %},VECTOR_SEARCH_BUCKET={% raw %}${{ vars.VECTOR_SEARCH_BUCKET_PROD }}{% endraw %}{%- endif %}{%- endif %}"
113
+ {%- endif %}
114
+