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.
- {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/METADATA +2 -2
- {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/RECORD +53 -51
- agents/adk_base/.template/templateconfig.yaml +1 -1
- agents/adk_gemini_fullstack/.template/templateconfig.yaml +1 -1
- agents/agentic_rag/.template/templateconfig.yaml +1 -1
- agents/agentic_rag/README.md +1 -1
- agents/live_api/tests/integration/test_server_e2e.py +7 -1
- llm.txt +3 -2
- src/base_template/Makefile +4 -3
- src/base_template/README.md +7 -2
- src/base_template/deployment/README.md +6 -121
- src/base_template/deployment/terraform/github.tf +284 -0
- src/base_template/deployment/terraform/providers.tf +5 -0
- src/base_template/deployment/terraform/variables.tf +40 -1
- src/base_template/deployment/terraform/vars/env.tfvars +7 -1
- src/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
- 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
- src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +114 -0
- src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
- src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +170 -0
- 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
- src/base_template/{deployment/cd/staging.yaml → {% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml } +7 -7
- src/cli/commands/create.py +120 -4
- src/cli/commands/list.py +1 -1
- src/cli/commands/setup_cicd.py +292 -298
- src/cli/utils/cicd.py +19 -7
- src/cli/utils/remote_template.py +4 -4
- src/cli/utils/template.py +67 -19
- src/deployment_targets/cloud_run/app/server.py +19 -0
- src/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +4 -3
- src/deployment_targets/cloud_run/deployment/terraform/service.tf +4 -3
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +35 -0
- src/deployment_targets/cloud_run/tests/load_test/README.md +1 -1
- src/frontends/live_api_react/frontend/package-lock.json +19 -16
- src/frontends/streamlit/frontend/side_bar.py +1 -1
- src/frontends/streamlit/frontend/utils/chat_utils.py +1 -1
- src/frontends/streamlit/frontend/utils/local_chat_history.py +2 -2
- src/resources/docs/adk-cheatsheet.md +1 -1
- src/resources/locks/uv-adk_base-agent_engine.lock +164 -131
- src/resources/locks/uv-adk_base-cloud_run.lock +177 -144
- src/resources/locks/uv-adk_gemini_fullstack-agent_engine.lock +164 -131
- src/resources/locks/uv-adk_gemini_fullstack-cloud_run.lock +177 -144
- src/resources/locks/uv-agentic_rag-agent_engine.lock +223 -190
- src/resources/locks/uv-agentic_rag-cloud_run.lock +251 -218
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +315 -485
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +358 -531
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +281 -249
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +323 -290
- src/resources/locks/uv-live_api-cloud_run.lock +350 -327
- src/resources/setup_cicd/cicd_variables.tf +0 -41
- src/resources/setup_cicd/github.tf +0 -87
- src/resources/setup_cicd/providers.tf +0 -39
- {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/entry_points.txt +0 -0
- {agent_starter_pack-0.9.2.dist-info → agent_starter_pack-0.10.0.dist-info}/licenses/LICENSE +0 -0
- /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
|
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 = "
|
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 = "
|
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 = [
|
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 = "
|
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
|
-
|
80
|
-
|
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
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
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 = [
|
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 = "
|
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
|
-
|
123
|
-
|
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
|
-
|
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
|
-
|
130
|
-
|
131
|
-
|
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 = [
|
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
|
+
|