View raw

1 #!/usr/bin/env bash 2 # hito pre-receive hook. The bare repository runs this hook before it moves a 3 # ref. The hook checks each candidate master revision in an isolated directory. 4 # A failed check rejects the push, so an unverified revision cannot deploy. 5 # 6 # deploy/setup.sh installs this hook and its trusted hito-ci helper. The helper 7 # is outside the received tree. A pushed revision cannot weaken this check. 8 # 9 # Style: Google Shell Style Guide. 10 11 set -euo pipefail 12 13 readonly DEPLOY_BRANCH="master" 14 readonly BARE="/srv/git/hito.git" 15 readonly SHARED="/srv/hito/shared" 16 readonly CI_HELPER="${BARE}/hooks/hito-ci" 17 readonly ZERO="0000000000000000000000000000000000000000" 18 19 export OPAMROOT="/srv/git/.opam" 20 export OPAMSWITCH="${SHARED}" 21 22 err() { 23 printf ' hito-verify: %s\n' "$*" >&2 24 } 25 26 fail() { 27 err "REJECTED: $*" 28 exit 1 29 } 30 31 verify_master() { 32 local old="$1" new="$2" 33 local stage buildlog 34 35 if [[ "${new}" == "${ZERO}" ]]; then 36 fail "master cannot be deleted" 37 fi 38 if [[ "${old}" != "${ZERO}" ]] \ 39 && ! git --git-dir="${BARE}" merge-base --is-ancestor "${old}" "${new}"; then 40 fail "master must advance by fast-forward" 41 fi 42 if [[ ! -x "${CI_HELPER}" ]]; then 43 fail "missing trusted CI helper; run deploy/setup.sh install" 44 fi 45 46 stage="$(mktemp -d /tmp/hito-verify.XXXXXX)" 47 trap 'rm -rf "${stage}"' RETURN 48 buildlog="${stage}/verify.log" 49 50 err "verifying candidate master ${new:0:12}" 51 git --git-dir="${BARE}" archive "${new}" | tar -x -C "${stage}" \ 52 || fail "archive candidate master" 53 54 eval "$(opam env --switch="${SHARED}" --set-switch)" 55 ( 56 cd "${stage}" 57 opam install . --deps-only --with-test --with-dev-setup -y >"${buildlog}" 2>&1 58 BUILD_DIR="_build-ci" sh "${CI_HELPER}" >>"${buildlog}" 2>&1 59 ) || { 60 tail -40 "${buildlog}" >&2 || true 61 fail "verification failed for ${new:0:12}" 62 } 63 64 err "verified candidate master ${new:0:12}" 65 } 66 67 main() { 68 local old new ref 69 while read -r old new ref; do 70 if [[ "${ref}" == "refs/heads/${DEPLOY_BRANCH}" ]]; then 71 verify_master "${old}" "${new}" 72 fi 73 done 74 } 75 76 main "$@" 77