-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloudbuild.yaml
More file actions
161 lines (150 loc) · 5.39 KB
/
Copy pathcloudbuild.yaml
File metadata and controls
161 lines (150 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# Cloud Build configuration for ProposalOS on GCP Cloud Run
# Replace _REGION and PROJECT_ID below with your values before running.
#
# Substitutions (edit these):
# _REGION: Your GCP region (e.g. us-central1, us-east1, europe-west1)
# _COMMIT_SHA: Defaults to $COMMIT_SHA (Cloud Build provides); use 'manual' for manual triggers
# _ENVIRONMENT: Target environment (staging or production)
# _DEPLOY_TARGET: Service name to deploy to
substitutions:
_REGION: 'us-central1' # TODO: Set your GCP region
_COMMIT_SHA: 'manual' # Use $COMMIT_SHA in triggers; override with --substitutions=_COMMIT_SHA=$(git rev-parse HEAD)
_ENVIRONMENT: 'staging' # staging or production
_DEPLOY_TARGET: '' # Will be set based on _ENVIRONMENT
steps:
# Step 0: Validate environment configuration (P0 - fail fast on config drift)
- name: 'node:20-alpine'
entrypoint: 'npm'
args: ['run', 'validate:env']
id: 'validate-env'
waitFor: ['-']
# Step 1: Set deploy target based on environment
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
if [ "$_ENVIRONMENT" = "production" ]; then
echo "DEPLOY_TARGET=proposal-engine" > /workspace/.env_vars
echo "MIN_INSTANCES=1" >> /workspace/.env_vars
echo "MAX_INSTANCES=5" >> /workspace/.env_vars
else
echo "DEPLOY_TARGET=proposal-engine-staging" > /workspace/.env_vars
echo "MIN_INSTANCES=0" >> /workspace/.env_vars
echo "MAX_INSTANCES=3" >> /workspace/.env_vars
fi
id: 'set-target'
waitFor: ['validate-env']
# Step 2: Source env vars
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
source /workspace/.env_vars
echo "Deploying to: $$DEPLOY_TARGET"
echo "Min instances: $$MIN_INSTANCES"
echo "Max instances: $$MAX_INSTANCES"
id: 'source-vars'
waitFor: ['set-target']
# Step 3: Build the container image with caching
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_COMMIT_SHA}'
- '-t'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_ENVIRONMENT}-latest'
- '--cache-from'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_ENVIRONMENT}-latest'
- '--build-arg'
# SKIP_ENV_VALIDATION=true is intentional: secrets are not available at Docker image
# build time. They are injected at Cloud Run startup via Secret Manager.
# The running container validates env via instrumentation.ts on first request.
- 'SKIP_ENV_VALIDATION=true'
- '.'
id: 'build-image'
waitFor: ['source-vars']
# Step 4: Push the container image to Artifact Registry
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_COMMIT_SHA}'
id: 'push-image'
waitFor: ['build-image']
# Step 5: Push latest tag for caching
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_ENVIRONMENT}-latest'
id: 'push-latest'
waitFor: ['push-image']
# Step 6: Deploy to Cloud Run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args:
- 'run'
- 'deploy'
- '$$DEPLOY_TARGET'
- '--image'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_COMMIT_SHA}'
- '--region'
- '${_REGION}'
- '--platform'
- 'managed'
- '--allow-unauthenticated'
- '--memory'
- '1Gi'
- '--cpu'
- '1'
- '--min-instances'
- '$$MIN_INSTANCES'
- '--max-instances'
- '$$MAX_INSTANCES'
- '--port'
- '8080'
- '--set-env-vars'
- 'NODE_ENV=${_ENVIRONMENT},DEPLOY_COMMIT=${_COMMIT_SHA}'
id: 'deploy'
waitFor: ['push-latest']
# Step 7: Run smoke tests (staging only)
- name: 'node:20-alpine'
entrypoint: 'npm'
args: ['run', 'final-audit']
id: 'smoke-test'
waitFor: ['deploy']
env:
- 'SMOKE_TEST_BASE_URL=https://${_ENVIRONMENT == "production" ? "proposal-engine" : "proposal-engine-staging"}-${_REGION}.run.app'
when:
condition: $_ENVIRONMENT == 'staging'
# Step 8: Send Slack notification
- name: 'curlimages/curl'
entrypoint: 'curl'
args:
- '-s'
- '-X'
- 'POST'
- '$$SLACK_WEBHOOK_URL'
- '-H'
- 'Content-Type: application/json'
- '-d'
- |
{
"text": "${_ENVIRONMENT == 'production' ? '✅' : '🚀'} Deploy to ${_ENVIRONMENT} ${_COMMIT_SHA:0:7}",
"attachments": [{
"color": "${_ENVIRONMENT == 'production' ? 'good' : 'warning'}",
"fields": [
{"title": "Environment", "value": "${_ENVIRONMENT}", "short": true},
{"title": "Commit", "value": "${_COMMIT_SHA}", "short": true},
{"title": "Region", "value": "${_REGION}", "short": true}
]
}]
}
id: 'notify'
waitFor: ['smoke-test']
env:
- 'SLACK_WEBHOOK_URL=$$SLACK_WEBHOOK_URL'
# Output images
images:
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_COMMIT_SHA}'
- '${_REGION}-docker.pkg.dev/$PROJECT_ID/proposal-engine/proposal-engine:${_ENVIRONMENT}-latest'