-
Notifications
You must be signed in to change notification settings - Fork 177
Expand file tree
/
Copy pathdeploy-pr-to-beta
More file actions
executable file
·334 lines (290 loc) · 10.5 KB
/
deploy-pr-to-beta
File metadata and controls
executable file
·334 lines (290 loc) · 10.5 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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#!/usr/bin/env bash
set -euo pipefail
# Usage: ./deploy-pr-to-beta [--staging-a|-sa | --staging-b|-sb | --staging-c|-sc | --staging <CANISTER_ID>] --end <front|back> <PR_NUMBER>
print_usage() {
cat <<EOF
Usage: $0 [--staging-a|-sa | --staging-b|-sb | --staging-c|-sc | --staging <CANISTER_ID>] --end <front|back> <PR_NUMBER>
Select which staging canister to upgrade and which end(s) to deploy.
Options:
--staging-a, -sa Use Staging A (backend: fgte5-ciaaa-aaaad-aaatq-cai, frontend: gjxif-ryaaa-aaaad-ae4ka-cai)
--staging-b, -sb Use Staging B (backend: jqajs-xiaaa-aaaad-aab5q-cai, frontend: uhh2r-oyaaa-aaaad-agbva-cai)
--staging-c, -sc Use Staging C (backend: y2aaj-miaaa-aaaad-aacxq-cai, frontend: uag4f-daaaa-aaaad-agbvq-cai)
--staging <CANISTER_ID> Use the provided canister id
--end <front|back> Which end(s) to deploy (can be specified multiple times)
-fe Shortcut for --end front
-be Shortcut for --end back
-h, --help Show this help
EOF
}
PR_NUMBER=""
STAGING_CANISTER_ID=""
STAGING_NAME=""
DEPLOY_FRONT=false
DEPLOY_BACK=false
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
print_usage
exit 0
;;
-sa|--staging-a)
STAGING_CANISTER_ID="fgte5-ciaaa-aaaad-aaatq-cai"
STAGING_NAME="a"
shift
;;
-sb|--staging-b)
STAGING_CANISTER_ID="jqajs-xiaaa-aaaad-aab5q-cai"
STAGING_NAME="b"
shift
;;
-sc|--staging-c)
STAGING_CANISTER_ID="y2aaj-miaaa-aaaad-aacxq-cai"
STAGING_NAME="c"
shift
;;
--staging)
shift
if [ $# -eq 0 ]; then
echo "Error: --staging requires an argument" >&2
print_usage
exit 1
fi
STAGING_CANISTER_ID="$1"
STAGING_NAME="custom"
shift
;;
--end)
shift
if [ $# -eq 0 ]; then
echo "Error: --end requires an argument (front or back)" >&2
print_usage
exit 1
fi
case "$1" in
front) DEPLOY_FRONT=true ;;
back) DEPLOY_BACK=true ;;
*)
echo "Error: --end value must be 'front' or 'back', got '$1'" >&2
print_usage
exit 1
;;
esac
shift
;;
-fe)
DEPLOY_FRONT=true
shift
;;
-be)
DEPLOY_BACK=true
shift
;;
--)
shift
break
;;
-*)
echo "Unknown option: $1" >&2
print_usage
exit 1
;;
*)
if [ -z "$PR_NUMBER" ]; then
PR_NUMBER="$1"
shift
else
echo "Unexpected argument: $1" >&2
print_usage
exit 1
fi
;;
esac
done
if [ -z "$PR_NUMBER" ]; then
echo "Error: PR number is required" >&2
print_usage
exit 1
fi
if [ -z "$STAGING_CANISTER_ID" ]; then
echo "Error: staging must be specified (use --staging-a/-sa, --staging-b/-sb, --staging-c/-sc, or --staging <CANISTER_ID>)" >&2
print_usage
exit 1
fi
if [ "$DEPLOY_FRONT" = false ] && [ "$DEPLOY_BACK" = false ]; then
echo "Error: --end must be specified (use --end front, --end back, -fe, or -be)" >&2
print_usage
exit 1
fi
if [ "$DEPLOY_FRONT" = true ] && [ "$STAGING_NAME" != "a" ] && [ "$STAGING_NAME" != "b" ] && [ "$STAGING_NAME" != "c" ]; then
echo "Error: Frontend deployment is only supported for Staging A, B, and C. Use --staging-a/-sa, --staging-b/-sb, or --staging-c/-sc." >&2
exit 1
fi
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$SCRIPTS_DIR/.."
cd "$ROOT_DIR"
REPO="dfinity/internet-identity"
WORKFLOW_FILE="canister-tests.yml"
WALLET_CANISTER_ID="cvthj-wyaaa-aaaad-aaaaq-cai"
# Map staging environment to its frontend canister ID
case "$STAGING_NAME" in
a) FRONTEND_CANISTER_ID="gjxif-ryaaa-aaaad-ae4ka-cai" ;;
b) FRONTEND_CANISTER_ID="uhh2r-oyaaa-aaaad-agbva-cai" ;;
c) FRONTEND_CANISTER_ID="uag4f-daaaa-aaaad-agbvq-cai" ;;
*) FRONTEND_CANISTER_ID="" ;;
esac
source "$SCRIPTS_DIR/frontend-arg-helpers.bash"
# -------------------------
# Prompt for frontend install args if deploying frontend
# -------------------------
FRONTEND_INSTALL_ARG=""
if [ "$DEPLOY_FRONT" = true ]; then
build_frontend_install_arg "$FRONTEND_CANISTER_ID"
fi
# Build the list of (artifact, canister, job_pattern, job_filter) tuples to deploy.
# job_pattern and job_filter are substrings matched against the job name, so the script
# is resilient to changes in matrix keys/order or GitHub's display-name formatting.
DEPLOYMENTS=()
if [ "$DEPLOY_BACK" = true ]; then
DEPLOYMENTS+=("internet_identity_backend.wasm.gz:$STAGING_CANISTER_ID:docker-build-internet_identity:internet_identity_backend.wasm.gz")
fi
if [ "$DEPLOY_FRONT" = true ]; then
DEPLOYMENTS+=("internet_identity_frontend.wasm.gz:$FRONTEND_CANISTER_ID:docker-build-internet_identity_frontend:docker-build-internet_identity_frontend")
fi
# -------------------------
# Cleanup handler
# -------------------------
cleanup() {
echo "Cleaning up temporary files..."
for pair in "${DEPLOYMENTS[@]}"; do
artifact="${pair%%:*}"
rm -f "$ROOT_DIR/$artifact.zip"
rm -f "$ROOT_DIR/$artifact"
done
}
trap cleanup EXIT
# -------------------------
# Get GitHub token from gh CLI
if command -v gh >/dev/null 2>&1; then
GITHUB_TOKEN="$(gh auth token)"
if [ -z "$GITHUB_TOKEN" ]; then
echo "Error: gh CLI is not authenticated or token unavailable."
exit 1
fi
else
echo "Error: gh CLI not found. Install and authenticate to access private workflows."
exit 1
fi
AUTH_HEADER="Authorization: token $GITHUB_TOKEN"
echo "Fetching workflow runs for PR #$PR_NUMBER..."
# Fetch the most recent workflow run for this PR (regardless of overall conclusion)
RUN_ID=$(curl -sf -H "$AUTH_HEADER" \
"https://api.github.com/repos/$REPO/actions/runs?event=push&per_page=100" \
| jq -r --arg PR "$PR_NUMBER" --arg WF "$WORKFLOW_FILE" '
[.workflow_runs[]
| select(.pull_requests[]?.number == ($PR|tonumber))
| select(.path == (".github/workflows/" + $WF))
]
| sort_by(.run_number)
| reverse
| .[0].id
')
if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then
echo "Error: No canister-tests.yml workflow run found for PR #$PR_NUMBER"
exit 1
fi
echo "Found workflow run ID: $RUN_ID"
# Fetch all jobs for this run, paginating to collect every page.
echo "Fetching jobs for workflow run..."
JOBS_JSON='{"jobs":[]}'
PAGE=1
while true; do
PAGE_JSON=$(curl -sf -H "$AUTH_HEADER" \
"https://api.github.com/repos/$REPO/actions/runs/$RUN_ID/jobs?per_page=100&page=$PAGE")
PAGE_COUNT=$(echo "$PAGE_JSON" | jq '.jobs | length')
if [ "$PAGE_COUNT" -eq 0 ]; then
break
fi
JOBS_JSON=$(jq -s '{ jobs: (.[0].jobs + .[1].jobs) }' \
<(echo "$JOBS_JSON") <(echo "$PAGE_JSON"))
if [ "$PAGE_COUNT" -lt 100 ]; then
break
fi
PAGE=$((PAGE + 1))
done
TOTAL_JOBS=$(echo "$JOBS_JSON" | jq '.jobs | length')
echo "Fetched $TOTAL_JOBS jobs."
for tuple in "${DEPLOYMENTS[@]}"; do
ARTIFACT_NAME="${tuple%%:*}"
remainder="${tuple#*:}"
CANISTER_ID="${remainder%%:*}"
remainder="${remainder#*:}"
JOB_PATTERN="${remainder%%:*}"
JOB_FILTER="${remainder#*:}"
ZIP_FILE="$ARTIFACT_NAME.zip"
echo ""
echo "=== Deploying $ARTIFACT_NAME to canister $CANISTER_ID ==="
# Find matching jobs by substring (resilient to matrix key/order changes)
MATCHING_JOBS=$(echo "$JOBS_JSON" | jq -c \
--arg PAT "$JOB_PATTERN" --arg FIL "$JOB_FILTER" '
.jobs | map(select(.name | contains($PAT) and contains($FIL)))
')
MATCH_COUNT=$(echo "$MATCHING_JOBS" | jq 'length')
if [ "$MATCH_COUNT" -eq 0 ]; then
echo "Error: No job matching '$JOB_PATTERN' + '$JOB_FILTER' found."
echo "Available jobs:"
echo "$JOBS_JSON" | jq -r '.jobs[] | " - \(.name) (\(.status)/\(.conclusion))"'
exit 1
fi
if [ "$MATCH_COUNT" -gt 1 ]; then
echo "Error: Multiple jobs match '$JOB_PATTERN' + '$JOB_FILTER':"
echo "$MATCHING_JOBS" | jq -r '.[] | " - \(.name) (\(.status)/\(.conclusion))"'
exit 1
fi
JOB_NAME=$(echo "$MATCHING_JOBS" | jq -r '.[0].name')
JOB_STATE=$(echo "$MATCHING_JOBS" | jq -r '.[0].status')
JOB_CONCLUSION=$(echo "$MATCHING_JOBS" | jq -r '.[0].conclusion')
if [ "$JOB_STATE" = "queued" ] || [ "$JOB_STATE" = "in_progress" ]; then
echo "Error: Required job '$JOB_NAME' has not completed yet (status: $JOB_STATE)"
exit 1
fi
if [ "$JOB_CONCLUSION" != "success" ]; then
echo "Error: Required job '$JOB_NAME' did not succeed (conclusion: $JOB_CONCLUSION)"
exit 1
fi
echo "Required job '$JOB_NAME' succeeded."
echo "Fetching artifact list..."
ARTIFACT_URL=$(curl -sf -H "$AUTH_HEADER" \
"https://api.github.com/repos/$REPO/actions/runs/$RUN_ID/artifacts?per_page=100" \
| jq -r --arg ART "$ARTIFACT_NAME" '
.artifacts[] | select(.name == $ART) | .archive_download_url
')
if [ -z "$ARTIFACT_URL" ] || [ "$ARTIFACT_URL" = "null" ]; then
echo "Error: Artifact not found: $ARTIFACT_NAME"
exit 1
fi
echo "Downloading artifact $ARTIFACT_NAME..."
curl -sfL -H "$AUTH_HEADER" -o "$ZIP_FILE" "$ARTIFACT_URL"
echo "Extracting ZIP..."
unzip -o "$ZIP_FILE" -d "$ROOT_DIR" >/dev/null
if [ ! -f "$ROOT_DIR/$ARTIFACT_NAME" ]; then
echo "Error: Extracted file not found: $ARTIFACT_NAME"
exit 1
fi
echo "Artifact extracted: $ARTIFACT_NAME"
# Build the install command with optional --argument for frontend
INSTALL_ARGS=()
if [ "$ARTIFACT_NAME" = "internet_identity_frontend.wasm.gz" ] && [ -n "$FRONTEND_INSTALL_ARG" ]; then
INSTALL_ARGS+=(--argument-type raw --argument "$FRONTEND_INSTALL_ARG")
fi
echo "Upgrading canister $CANISTER_ID..."
dfx canister \
--network ic \
--wallet "$WALLET_CANISTER_ID" \
install "$CANISTER_ID" \
--mode upgrade \
--wasm "$ROOT_DIR/$ARTIFACT_NAME" \
${INSTALL_ARGS[@]+"${INSTALL_ARGS[@]}"}
echo "Upgrade of $CANISTER_ID complete."
done
echo ""
echo "All deployments complete."