11#! /usr/bin/env bash
22set -euo pipefail
33
4- # Usage: ./deploy-pr-to-beta [--staging-a|-sa | --staging-b|-sb | --staging-c|-sc | --staging <CANISTER_ID>] <PR_NUMBER>
4+ # Usage: ./deploy-pr-to-beta [--staging-a|-sa | --staging-b|-sb | --staging-c|-sc | --staging <CANISTER_ID>] --end <front|back> <PR_NUMBER>
55
66print_usage () {
77 cat << EOF
8- Usage: $0 [--staging-a|-sa | --staging-b|-sb | --staging-c|-sc | --staging <CANISTER_ID>] <PR_NUMBER>
8+ Usage: $0 [--staging-a|-sa | --staging-b|-sb | --staging-c|-sc | --staging <CANISTER_ID>] --end <front|back> <PR_NUMBER>
99
10- Select which staging canister to upgrade.
10+ Select which staging canister to upgrade and which end(s) to deploy .
1111
1212Options:
1313 --staging-a, -sa Use Staging A (fgte5-ciaaa-aaaad-aaatq-cai)
1414 --staging-b, -sb Use Staging B (jqajs-xiaaa-aaaad-aab5q-cai)
1515 --staging-c, -sc Use Staging C (y2aaj-miaaa-aaaad-aacxq-cai)
1616 --staging <CANISTER_ID> Use the provided canister id
17+ --end <front|back> Which end(s) to deploy (can be specified multiple times)
18+ -fe Shortcut for --end front
19+ -be Shortcut for --end back
1720 -h, --help Show this help
1821EOF
1922}
2023
2124PR_NUMBER=" "
2225STAGING_CANISTER_ID=" "
26+ STAGING_NAME=" "
27+ DEPLOY_FRONT=false
28+ DEPLOY_BACK=false
2329
2430while [[ $# -gt 0 ]]; do
2531 case " $1 " in
@@ -29,14 +35,17 @@ while [[ $# -gt 0 ]]; do
2935 ;;
3036 -sa|--staging-a)
3137 STAGING_CANISTER_ID=" fgte5-ciaaa-aaaad-aaatq-cai"
38+ STAGING_NAME=" a"
3239 shift
3340 ;;
3441 -sb|--staging-b)
3542 STAGING_CANISTER_ID=" jqajs-xiaaa-aaaad-aab5q-cai"
43+ STAGING_NAME=" b"
3644 shift
3745 ;;
3846 -sc|--staging-c)
3947 STAGING_CANISTER_ID=" y2aaj-miaaa-aaaad-aacxq-cai"
48+ STAGING_NAME=" c"
4049 shift
4150 ;;
4251 --staging)
@@ -47,6 +56,33 @@ while [[ $# -gt 0 ]]; do
4756 exit 1
4857 fi
4958 STAGING_CANISTER_ID=" $1 "
59+ STAGING_NAME=" custom"
60+ shift
61+ ;;
62+ --end)
63+ shift
64+ if [ $# -eq 0 ]; then
65+ echo " Error: --end requires an argument (front or back)" >&2
66+ print_usage
67+ exit 1
68+ fi
69+ case " $1 " in
70+ front) DEPLOY_FRONT=true ;;
71+ back) DEPLOY_BACK=true ;;
72+ * )
73+ echo " Error: --end value must be 'front' or 'back', got '$1 '" >&2
74+ print_usage
75+ exit 1
76+ ;;
77+ esac
78+ shift
79+ ;;
80+ -fe)
81+ DEPLOY_FRONT=true
82+ shift
83+ ;;
84+ -be)
85+ DEPLOY_BACK=true
5086 shift
5187 ;;
5288 --)
@@ -83,25 +119,153 @@ if [ -z "$STAGING_CANISTER_ID" ]; then
83119 exit 1
84120fi
85121
122+ if [ " $DEPLOY_FRONT " = false ] && [ " $DEPLOY_BACK " = false ]; then
123+ echo " Error: --end must be specified (use --end front, --end back, -fe, or -be)" >&2
124+ print_usage
125+ exit 1
126+ fi
127+
128+ if [ " $DEPLOY_FRONT " = true ] && [ " $STAGING_NAME " != " a" ]; then
129+ echo " Error: Frontend deployment is not yet supported for Staging B, C, or custom canister IDs. Use --staging-a/-sa for frontend deployment." >&2
130+ exit 1
131+ fi
132+
86133SCRIPTS_DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd ) "
87134ROOT_DIR=" $SCRIPTS_DIR /.."
88135cd " $ROOT_DIR "
89136
90137REPO=" dfinity/internet-identity"
91138WORKFLOW_FILE=" canister-tests.yml"
92- ARTIFACT_NAME=" internet_identity_production.wasm.gz"
93- ZIP_FILE=" $ARTIFACT_NAME .zip"
94- EXTRACTED_FILE=" $ARTIFACT_NAME "
95139WALLET_CANISTER_ID=" cvthj-wyaaa-aaaad-aaaaq-cai"
96- BETA_CANISTER_ID=" $STAGING_CANISTER_ID "
140+ FRONTEND_CANISTER_ID=" gjxif-ryaaa-aaaad-ae4ka-cai"
141+
142+ # -------------------------
143+ # Prompt for a single Candid field value.
144+ # Usage: prompt_field <field_label> <current_value>
145+ # Prints the (possibly updated) value to stdout.
146+ # -------------------------
147+ prompt_field () {
148+ local label=" $1 "
149+ local current=" $2 "
150+ echo " " >&2
151+ echo " $label = $current " >&2
152+ read -r -p " Keep current value? [Y/n]: " answer < /dev/tty >&2
153+ if [[ " $answer " =~ ^[Nn] ]]; then
154+ read -r -p " Enter new value for $label : " new_value < /dev/tty >&2
155+ echo " $new_value "
156+ else
157+ echo " $current "
158+ fi
159+ }
160+
161+ # -------------------------
162+ # Build InternetIdentityFrontendInit Candid argument interactively.
163+ # Fetches current config from the canister, then prompts field-by-field.
164+ # Sets FRONTEND_INSTALL_ARG with the resulting Candid record.
165+ # -------------------------
166+ build_frontend_install_arg () {
167+ local canister_id=" $1 "
168+ local config_url=" https://${canister_id} .icp0.io/.config"
169+
170+ echo " "
171+ echo " Fetching current frontend config from $config_url ..."
172+ local raw_config
173+ raw_config=$( curl -sfL " $config_url " )
174+ if [ -z " $raw_config " ]; then
175+ echo " Error: Could not fetch current config from $config_url " >&2
176+ exit 1
177+ fi
178+
179+ echo " "
180+ echo " Current frontend config:"
181+ echo " $raw_config "
182+ echo " "
183+ echo " Configure install arguments (press Enter to keep each current value):"
184+
185+ # Parse individual fields from the Candid text output.
186+ # We use grep + sed to extract the value portion after "field_name = ".
187+ local current_backend_canister_id
188+ current_backend_canister_id=$( echo " $raw_config " | grep ' backend_canister_id' | sed ' s/.*= *//;s/ *;$//' )
189+ local current_backend_origin
190+ current_backend_origin=$( echo " $raw_config " | grep ' backend_origin' | sed ' s/.*= *//;s/ *;$//' )
191+ local current_related_origins
192+ current_related_origins=$( echo " $raw_config " | sed -n ' /related_origins/,/}/p' | tr ' \n' ' ' | sed ' s/.*= *//;s/ *;[[:space:]]*$//' )
193+ local current_fetch_root_key
194+ current_fetch_root_key=$( echo " $raw_config " | grep ' fetch_root_key' | sed ' s/.*= *//;s/ *;$//' )
195+ local current_analytics_config
196+ current_analytics_config=$( echo " $raw_config " | grep ' analytics_config' | sed ' s/.*= *//;s/ *;$//' )
197+ local current_dummy_auth
198+ current_dummy_auth=$( echo " $raw_config " | grep ' dummy_auth' | sed ' s/.*= *//;s/ *;$//' )
199+
200+ local val_backend_canister_id
201+ val_backend_canister_id=$( prompt_field " backend_canister_id" " $current_backend_canister_id " )
202+ local val_backend_origin
203+ val_backend_origin=$( prompt_field " backend_origin" " $current_backend_origin " )
204+ local val_related_origins
205+ val_related_origins=$( prompt_field " related_origins" " $current_related_origins " )
206+ local val_fetch_root_key
207+ val_fetch_root_key=$( prompt_field " fetch_root_key" " $current_fetch_root_key " )
208+ local val_analytics_config
209+ val_analytics_config=$( prompt_field " analytics_config" " $current_analytics_config " )
210+ local val_dummy_auth
211+ val_dummy_auth=$( prompt_field " dummy_auth" " $current_dummy_auth " )
212+
213+ local candid_arg=" (record { backend_canister_id = ${val_backend_canister_id} ; backend_origin = ${val_backend_origin} ; related_origins = ${val_related_origins} ; fetch_root_key = ${val_fetch_root_key} ; analytics_config = ${val_analytics_config} ; dummy_auth = ${val_dummy_auth} })"
214+
215+ echo " "
216+ echo " Install argument (Candid):"
217+ echo " $candid_arg "
218+ echo " "
219+
220+ echo " Encoding argument with didc..."
221+ local encoded
222+ encoded=$( didc encode \
223+ -d ./src/internet_identity_frontend/internet_identity_frontend.did \
224+ -t ' (InternetIdentityFrontendInit)' \
225+ " $candid_arg " )
226+ if [ -z " $encoded " ]; then
227+ echo " Error: didc encode failed" >&2
228+ exit 1
229+ fi
230+
231+ FRONTEND_INSTALL_ARG=" $encoded "
232+
233+ echo " Encoded argument: $FRONTEND_INSTALL_ARG "
234+ echo " "
235+ read -r -p " Proceed with this argument? [Y/n]: " confirm < /dev/tty
236+ if [[ " $confirm " =~ ^[Nn] ]]; then
237+ echo " Aborted by user." >&2
238+ exit 1
239+ fi
240+ }
241+
242+ # -------------------------
243+ # Prompt for frontend install args if deploying frontend
244+ # -------------------------
245+ FRONTEND_INSTALL_ARG=" "
246+ if [ " $DEPLOY_FRONT " = true ]; then
247+ build_frontend_install_arg " $FRONTEND_CANISTER_ID "
248+ fi
249+
250+ # Build the list of (artifact, canister) pairs to deploy
251+ DEPLOYMENTS=()
252+ if [ " $DEPLOY_BACK " = true ]; then
253+ DEPLOYMENTS+=(" internet_identity_production.wasm.gz:$STAGING_CANISTER_ID " )
254+ fi
255+ if [ " $DEPLOY_FRONT " = true ]; then
256+ DEPLOYMENTS+=(" internet_identity_frontend.wasm.gz:$FRONTEND_CANISTER_ID " )
257+ fi
97258
98259# -------------------------
99260# Cleanup handler
100261# -------------------------
101262cleanup () {
102263 echo " Cleaning up temporary files..."
103- rm -f " $ROOT_DIR /$ZIP_FILE "
104- rm -f " $ROOT_DIR /$EXTRACTED_FILE "
264+ for pair in " ${DEPLOYMENTS[@]} " ; do
265+ artifact=" ${pair%%:* } "
266+ rm -f " $ROOT_DIR /$artifact .zip"
267+ rm -f " $ROOT_DIR /$artifact "
268+ done
105269}
106270trap cleanup EXIT
107271# -------------------------
@@ -129,6 +293,7 @@ RUN_ID=$(curl -sf -H "$AUTH_HEADER" \
129293 [.workflow_runs[]
130294 | select(.pull_requests[]?.number == ($PR|tonumber))
131295 | select(.path == (".github/workflows/" + $WF))
296+ | select(.status == "completed" and .conclusion == "success")
132297 ]
133298 | sort_by(.run_number)
134299 | reverse
142307
143308echo " Found workflow run ID: $RUN_ID "
144309
145- echo " Fetching artifact list..."
146- ARTIFACT_URL=$( curl -sf -H " $AUTH_HEADER " \
147- " https://api.github.com/repos/$REPO /actions/runs/$RUN_ID /artifacts" \
148- | jq -r --arg ART " $ARTIFACT_NAME " '
149- .artifacts[] | select(.name == $ART) | .archive_download_url
150- ' )
310+ for pair in " ${DEPLOYMENTS[@]} " ; do
311+ ARTIFACT_NAME=" ${pair%%:* } "
312+ CANISTER_ID=" ${pair##*: } "
313+ ZIP_FILE=" $ARTIFACT_NAME .zip"
151314
152- if [ -z " $ARTIFACT_URL " ] || [ " $ARTIFACT_URL " = " null" ]; then
153- echo " Error: Artifact not found: $ARTIFACT_NAME "
154- exit 1
155- fi
315+ echo " "
316+ echo " === Deploying $ARTIFACT_NAME to canister $CANISTER_ID ==="
156317
157- echo " Downloading artifact $ARTIFACT_NAME ..."
158- curl -sfL -H " $AUTH_HEADER " -o " $ZIP_FILE " " $ARTIFACT_URL "
318+ echo " Fetching artifact list..."
319+ ARTIFACT_URL=$( curl -sf -H " $AUTH_HEADER " \
320+ " https://api.github.com/repos/$REPO /actions/runs/$RUN_ID /artifacts?per_page=100" \
321+ | jq -r --arg ART " $ARTIFACT_NAME " '
322+ .artifacts[] | select(.name == $ART) | .archive_download_url
323+ ' )
159324
160- echo " Extracting ZIP..."
161- unzip -o " $ZIP_FILE " -d " $ROOT_DIR " > /dev/null
325+ if [ -z " $ARTIFACT_URL " ] || [ " $ARTIFACT_URL " = " null" ]; then
326+ echo " Error: Artifact not found: $ARTIFACT_NAME "
327+ exit 1
328+ fi
162329
163- if [ ! -f " $ROOT_DIR /$EXTRACTED_FILE " ]; then
164- echo " Error: Extracted file not found: $EXTRACTED_FILE "
165- exit 1
166- fi
330+ echo " Downloading artifact $ARTIFACT_NAME ..."
331+ curl -sfL -H " $AUTH_HEADER " -o " $ZIP_FILE " " $ARTIFACT_URL "
167332
168- echo " Artifact extracted: $EXTRACTED_FILE "
333+ echo " Extracting ZIP..."
334+ unzip -o " $ZIP_FILE " -d " $ROOT_DIR " > /dev/null
169335
170- # Upgrade the beta II canister with the .wasm.gz file
171- echo " Upgrading canister $BETA_CANISTER_ID ..."
172- dfx canister \
173- --network ic \
174- --wallet " $WALLET_CANISTER_ID " \
175- install " $BETA_CANISTER_ID " \
176- --mode upgrade \
177- --wasm " $ROOT_DIR /$EXTRACTED_FILE "
336+ if [ ! -f " $ROOT_DIR /$ARTIFACT_NAME " ]; then
337+ echo " Error: Extracted file not found: $ARTIFACT_NAME "
338+ exit 1
339+ fi
340+
341+ echo " Artifact extracted: $ARTIFACT_NAME "
342+
343+ # Build the install command with optional --argument for frontend
344+ INSTALL_ARGS=()
345+ if [ " $ARTIFACT_NAME " = " internet_identity_frontend.wasm.gz" ] && [ -n " $FRONTEND_INSTALL_ARG " ]; then
346+ INSTALL_ARGS+=(--argument-type raw --argument " $FRONTEND_INSTALL_ARG " )
347+ fi
348+
349+ echo " Upgrading canister $CANISTER_ID ..."
350+ dfx canister \
351+ --network ic \
352+ --wallet " $WALLET_CANISTER_ID " \
353+ install " $CANISTER_ID " \
354+ --mode upgrade \
355+ --wasm " $ROOT_DIR /$ARTIFACT_NAME " \
356+ ${INSTALL_ARGS[@]+" ${INSTALL_ARGS[@]} " }
357+
358+ echo " Upgrade of $CANISTER_ID complete."
359+ done
178360
179- echo " Upgrade complete."
361+ echo " "
362+ echo " All deployments complete."
0 commit comments