checkout/scripts/checkout.sh

121 lines
No EOL
3.5 KiB
Bash
Executable file

#!/usr/bin/env bash
shopt -s extglob
ACTION_INPUT_TOKEN="${ACTION_INPUT_TOKEN:?}"
ACTION_INPUT_REPOSITORY="${ACTION_INPUT_REPOSITORY:?}"
ACTION_INPUT_PATH="${ACTION_INPUT_PATH:?}"
ACTION_INPUT_REF="${ACTION_INPUT_REF:?}"
error() {
echo "$*" 1>&2 ; exit 1;
}
# ensure we are in the right place
[[ -z "${GITHUB_WORKSPACE:-}" ]] || { cd "${GITHUB_WORKSPACE}" || error ; }
git config --global --add protocol.version 2
git init -q "${ACTION_INPUT_PATH}" && { cd "${ACTION_INPUT_PATH}" || error ; }
git config --local gc.auto 0
# the server url and uri are important for determining the default checkout url
GITHUB_SERVER_URL="${GITHUB_SERVER_URL:?}"
GITHUB_SERVER_URI="${GITHUB_SERVER_URL//http?(s):\/\//}"
# use https instead of everything else
git config --add url."${GITHUB_SERVER_URL}/".insteadOf "git@${GITHUB_SERVER_URI}:"
git config --add url."${GITHUB_SERVER_URL}/".insteadOf "ssh://git@${GITHUB_SERVER_URI}/"
git config --add url."${GITHUB_SERVER_URL}/".insteadOf "git://${GITHUB_SERVER_URI}/"
# prepare git config extra header for https auth
BASE64="base64 --wrap 0"
echo "" | ${BASE64} >/dev/null 2>&1 || BASE64="base64"
echo "" | ${BASE64} >/dev/null 2>&1 || BASE64="openssl base64 -A"
echo "" | ${BASE64} >/dev/null 2>&1
GIT_HTTP_EXTRAHEADER="AUTHORIZATION: basic $(echo -n "x-access-token:${ACTION_INPUT_TOKEN}" | ${BASE64})"
git config --local --add http."${GITHUB_SERVER_URL}".extraheader "${GIT_HTTP_EXTRAHEADER}"
# add the repository as remote
git remote add origin "${ACTION_INPUT_REPOSITORY}"
git_default_refspec() {
git ls-remote --symref origin HEAD | { read -r _ ref name ; echo "${ref}" ; }
}
git_resolve_refspec() {
# shellcheck disable=SC2068
git ls-remote origin $@ | { read -r sha ref _ ; echo "${sha} ${ref}" ; }
}
fetch() {
# shellcheck disable=SC2068
git fetch --no-tags --prune --no-recurse-submodules --depth=1 origin $@
}
checkout() {
# shellcheck disable=SC2068
git checkout --force $@
}
# the checkout is based on a commit hash
if [[ ${ACTION_INPUT_REF:-} =~ ^[0-9a-f]{5,40}$ ]]
then
fetch "${ACTION_INPUT_REF}" && checkout "${ACTION_INPUT_REF}"
exit
fi
# update selected ref when no input is given to remote default branch
: "${ACTION_INPUT_REF:=$( git_default_refspec )}"
# TODO: check if repo is workflow repo, if so, use commit sha from env
# like GITHUB_REF and GITHUB_SHA
read -r GIT_SHA GIT_REF _ <<< "$( git_resolve_refspec "${ACTION_INPUT_REF}" )"
: "${GIT_SHA:?}" "${GIT_REF:?}"
# we always use the refspec with the commit sha as source to prevent
# race conditions when running on a frequently used branch
checkout_head() {
local name="${GIT_REF#refs\/heads\/}"
local remote="refs/remotes/origin/${name}"
fetch "+${GIT_SHA}:${remote}"
checkout -B "${name}" "${remote}"
}
checkout_pull() {
local name="${GIT_REF#refs\/pull\/}"
local remote="refs/remotes/pull/${name}"
fetch "+${GIT_SHA}:${remote}"
# pull requests have a special treatment for the branch name. The name
# is determined by the branch the pull request is targeting.
local branch="${GITHUB_BASE_REF:-$( git_default_refspec )}"
checkout -B "${branch#refs\/heads\/}" "${remote}"
}
checkout_tag() {
local name="${GIT_REF#refs\/tags\/}"
local remote="refs/tags/${name}"
fetch "+${GIT_SHA}:${remote}"
checkout "${remote}"
}
case "${GIT_REF}" in
# heads and pull are a branch based checkout
refs/heads/*) checkout_head ;;
refs/pull/* ) checkout_pull ;;
# tags are a detached head checkout
refs/tags/* ) checkout_tag ;;
*) error "ref type '${GIT_REF}' is unknown" ;;
esac