#!/usr/bin/env bash # Publish the packaged artifacts to the env's S3 bucket and roll the box to them. # Run by build-artifacts.yml AFTER aws creds are configured (env: ENV, BUCKET, # DEPLOY_DOC). Each release is stored immutably under releases//. # # releases/latest/ (what the box's deploy.sh pulls) is advanced TRANSACTIONALLY: # it is pointed at the new release, the box is rolled, and ONLY on a successful # roll is it kept — a failed roll reverts releases/latest/ to the prior release so # a later box boot / replacement never self-deploys a release that failed to come # up. releases/last-good/ (rollback fallback) is advanced only after success and # means "last release whose deploy.sh brought the service up active" (deploy.sh # gates on `systemctl is-active`), not merely "last uploaded". # # The fire/wait/gate against the box lives in roll-box.sh (shared with rollback.sh); # the deploy is fired by TAG (project=open-swe,env=), exactly what the app # deploy role's tag-scoped ssm:SendCommand allows. set -euo pipefail : "${ENV:?}" "${BUCKET:?}" "${DEPLOY_DOC:?}" SHA="${GITHUB_SHA:?}" [ -f app.tar.gz ] && [ -f spa.tar.gz ] || { echo "ERROR: artifacts not built" >&2; exit 1; } HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Re-point releases/latest/ at the release stored under releases//, recording # the sha so the pointer is self-describing (used to revert on failure). point_latest() { local s="$1" f for f in app.tar.gz spa.tar.gz; do aws s3 cp "s3://${BUCKET}/releases/${s}/${f}" "s3://${BUCKET}/releases/latest/${f}" done printf '%s\n' "${s}" | aws s3 cp - "s3://${BUCKET}/releases/latest/sha.txt" } # Which release does latest point at right now? (empty on the very first deploy.) PREV_SHA="$(aws s3 cp "s3://${BUCKET}/releases/latest/sha.txt" - 2>/dev/null | tr -d '[:space:]' || true)" echo "==> upload release ${SHA} to s3://${BUCKET}/releases/${SHA}/" for f in app.tar.gz spa.tar.gz; do aws s3 cp "${f}" "s3://${BUCKET}/releases/${SHA}/${f}" done echo "==> point releases/latest/ -> ${SHA} (was ${PREV_SHA:-})" point_latest "${SHA}" # Roll the box to releases/latest/. On a non-Success aggregate, roll-box.sh exits # non-zero; revert latest to the prior release so no later boot pulls the bad one. if ! ROLL_COMMENT="release ${SHA}" bash "${HERE}/roll-box.sh"; then if [ -n "${PREV_SHA}" ]; then echo "!! deploy failed — reverting releases/latest/ -> ${PREV_SHA}" >&2 point_latest "${PREV_SHA}" else echo "!! deploy failed on the FIRST release — leaving releases/latest/ = ${SHA} (no prior release to revert to)" >&2 fi exit 1 fi # Roll succeeded (service came up active) -> this release is now the known-good one. echo "==> mark releases/last-good/ = ${SHA} (rollback fallback target)" for f in app.tar.gz spa.tar.gz; do aws s3 cp "s3://${BUCKET}/releases/${SHA}/${f}" "s3://${BUCKET}/releases/last-good/${f}" done printf '%s\n' "${SHA}" | aws s3 cp - "s3://${BUCKET}/releases/last-good/sha.txt" echo "==> ${ENV} rolled to release ${SHA} (now last-good)"