Skip to content
109 linesCodeBlameRaw
1#!/usr/bin/env bash
2# The g1t/deploy action's work (see README.md): opens a g1t.page build for
3# this job with POST /repos/{owner}/{repo}/deployments/builds, masks its
4# token and the project's build secrets, and runs `g1t-runner deploy` in
5# the checkout with them. Reads the action's inputs as INPUT_* variables.
6set -euo pipefail
7
8api="${GITHUB_API_URL:-https://api.g1t.sh}"
9api="${api%/}"
10repo="${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is not set: run this in a g1t Actions job.}"
11if [ -z "${INPUT_TOKEN:-}" ]; then
12 echo "::error::The token input is empty: give the job's own token, \${{ github.token }}, with permissions: deployments: write."
13 exit 1
14fi
15
16# JSON, with jq where there is one, else Python.
17if command -v jq >/dev/null 2>&1; then
18 field() { jq -r --arg key "$1" '.[$key] // empty | if type == "object" or type == "array" then tojson else tostring end'; }
19 values() { jq -r --arg key "$1" '.[$key] // {} | .[] | tostring'; }
20 message() { jq -r '.message // .error.message // empty' 2>/dev/null || true; }
21 body() { jq -cn --arg project "$1" --arg sha "$2" '{project: $project, sha: $sha} | with_entries(select(.value != ""))'; }
22elif command -v python3 >/dev/null 2>&1; then
23 field() {
24 python3 -c 'import json, sys
25v = json.load(sys.stdin).get(sys.argv[1])
26if v is None: sys.exit(0)
27print(json.dumps(v, separators=(",", ":")) if isinstance(v, (dict, list)) else str(v).lower() if isinstance(v, bool) else v)' "$1"
28 }
29 values() { python3 -c 'import json, sys
30for v in (json.load(sys.stdin).get(sys.argv[1]) or {}).values(): print(v)' "$1"; }
31 message() { python3 -c 'import json, sys
32d = json.load(sys.stdin); print(d.get("message") or (d.get("error") or {}).get("message") or "")' 2>/dev/null || true; }
33 body() { python3 -c 'import json, sys
34print(json.dumps({k: v for k, v in (("project", sys.argv[1]), ("sha", sys.argv[2])) if v}))' "$1" "$2"; }
35else
36 echo "::error::g1t/deploy needs jq or python3 on the machine."
37 exit 1
38fi
39
40# The build, opened for this job.
41request="$(body "${INPUT_PROJECT:-}" "${INPUT_SHA:-}")"
42answer_file="$(mktemp)"
43trap 'rm -f "${answer_file}"' EXIT
44status="$(curl -sS -o "${answer_file}" -w '%{http_code}' -X POST \
45 -H "Authorization: Bearer ${INPUT_TOKEN}" \
46 -H "Content-Type: application/json" \
47 -H "Accept: application/json" \
48 --data "${request}" \
49 "${api}/repos/${repo}/deployments/builds")" || {
50 echo "::error::Could not reach ${api} to open the build."
51 exit 1
52}
53answer="$(cat "${answer_file}")"
54if [ "${status}" != "200" ]; then
55 why="$(message <<<"${answer}")"
56 echo "::error::g1t did not open the build (${status}): ${why:-no reason given}"
57 exit 1
58fi
59
60# Nothing secret is printed before it is masked.
61build_token="$(field token <<<"${answer}")"
62echo "::add-mask::${build_token}"
63while IFS= read -r secret; do
64 [ -n "${secret}" ] && echo "::add-mask::${secret}"
65done < <(values build_secrets <<<"${answer}")
66
67deployment_id="$(field deploy_id <<<"${answer}")"
68kind="$(field kind <<<"${answer}")"
69url="$(field url <<<"${answer}")"
70project="$(field project <<<"${answer}")"
71branch="$(field branch <<<"${answer}")"
72trusted="$(field trusted <<<"${answer}")"
73{
74 echo "deployment-id=${deployment_id}"
75 echo "kind=${kind}"
76 echo "url=${url}"
77} >>"${GITHUB_OUTPUT:-/dev/null}"
78
79if [ "${kind}" = "production" ]; then
80 echo "Building ${project} for production, at ${url}"
81else
82 echo "Building the ${branch} preview of ${project}, at ${url}"
83fi
84if [ "${trusted}" != "true" ]; then
85 echo "::notice::This run is not trusted with the project's build secrets (a pull request from outside, or a run that needed approval): it builds without them."
86fi
87
88# What the step gives wins over the project's own settings.
89pick() { if [ -n "$1" ]; then echo "$1"; else field "$2" <<<"${answer}"; fi; }
90export DEPLOY_ID="${deployment_id}"
91export DEPLOY_TOKEN="${build_token}"
92export G1T_API="${api}"
93export ROOT_DIR="$(pick "${INPUT_ROOT_DIR:-}" root_dir)"
94export BUILD_COMMAND="$(pick "${INPUT_BUILD_COMMAND:-}" build_command)"
95export OUTPUT_DIR="$(pick "${INPUT_OUTPUT_DIR:-}" output_dir)"
96export BUILD_ENV="$(field build_env <<<"${answer}")"
97export BUILD_SECRETS="$(field build_secrets <<<"${answer}")"
98unset GIT_REMOTE
99
100runner="$(bash "${GITHUB_ACTION_PATH:-$(dirname "$0")}/runner.sh")"
101if ! "${runner}" deploy --help 2>/dev/null | grep -q DEPLOY_ID; then
102 echo "::error::${runner} is older than g1t/deploy needs: update it (g1t-runner update), or let the action download it by taking it off PATH."
103 exit 1
104fi
105"${runner}" deploy
106echo "Deployed: ${url}"
107if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
108 echo "Deployed ${project} (${kind}) to ${url}" >>"${GITHUB_STEP_SUMMARY}"
109fi