Skip to content

Instantly share code, notes, and snippets.

@allex
Last active November 26, 2021 09:57
Show Gist options
  • Save allex/3bed8534d89fa58ff47b9d98752e3fef to your computer and use it in GitHub Desktop.
Save allex/3bed8534d89fa58ff47b9d98752e3fef to your computer and use it in GitHub Desktop.
#!/bin/bash
# By allex_wang
# GistID: 3bed8534d89fa58ff47b9d98752e3fef
# Last Modified: Fri Sep 24, 2021 10:51
set -e
PROG=$(basename "$0")
error() { echo >&2 "[$PROG]: ${*}"; }
[ "${CI-}" != true ] && { error "Runner context invalid"; exit 1; }
[ "${CI_DEBUG_TRACE-}" = "true" ] && set -x
# CI_X_DOCKER_IMAGE_NAME, docker image name, use project name instead."
# add image name with registry additionally
release_name=${CI_X_DOCKER_IMAGE_NAME:-${CI_PROJECT_NAME}}
registry="${CI_X_DOCKER_HUB:-}"
if [ "$registry" ]; then
release_name="$registry/${release_name#$registry/}"
fi
# CI_PROJECT_RELEASE_TAG, docker image tag name
release_tag="${CI_PROJECT_RELEASE_TAG:?Release Tag Invalid}"
# Build the final docker image name. eg: hub.tidu.io/test/test-ci:1.5.0
release_image="${release_name}:${release_tag}"
upload_mirror_registry ()
{
local opts=${CI_X_DOCKER_MIRROR_OPTS:-}
# Evalute simple VAR-Template substitute, %{tag} -> ${release_tag}
opts=${opts//%\{tag\}/${release_tag}}
echo "Upload docker image to mirror registry ..."
docker pull "$release_image" >/dev/null
eval "(set -x; pushimage.sh -t $release_image ${opts})"
docker rmi -f "$release_image" >/dev/null
}
cat <<-__DOCKER_BUILD_ARGS__ >./.dockerargs
BUILD_GIT_HEAD=${CI_BUILD_REF}
BUILD_VERSION=${CI_BUILD_VERSION}
VERBOSE=${CI_DEBUG_TRACE:-0}
__DOCKER_BUILD_ARGS__
awk '/^(CI_COMMIT|CI_BUILD|CI_PROJECT).*=/' env > ./.dockerenv
docker_file="${CI_BUILD_SPECS_DIR%/}/Dockerfile"
docker-build.sh \
-t "$release_image" \
-f "$docker_file" . \
--env ./.dockerenv \
--build-arg-file ./.dockerargs \
--push \
${CI_X_DOCKER_ARCHS:+--platform "${CI_X_DOCKER_ARCHS}"} \
${CI_X_DOCKER_BASE_IMAGE:+--base-image ${CI_X_DOCKER_BASE_IMAGE}} \
${CI_X_DOCKER_PATCH_IMAGE:+--patch-image ${CI_X_DOCKER_PATCH_IMAGE}}
if [ "${CI_X_DOCKER_MIRROR:-false}" = "true" ]; then
upload_mirror_registry
fi
#!/bin/bash
# vim: set ft=sh fdm=marker ts=2 sw=2 sts=2 tw=85 et:
set -eEu -o pipefail
[ "${CI-}" != true ] && exit 1
# ================================================
# Description: ci helper for deploy static distributes
#
# Last Modified: Fri Nov 26, 2021 17:33
# Author: Allex Wang ([email protected])
#
# Usage:
# ./git-deploy-bundle --proj-name cmp-ui [ ... ]
# (based on and forward `git-deploy` parameters)
#
# GistID: 3bed8534d89fa58ff47b9d98752e3fef
# GistURL: https://gist.github.com/allex/3bed8534d89fa58ff47b9d98752e3fef
# ================================================
[ "${CI_DEBUG_TRACE-}" = "true" ] && set -x
PROG=$(basename "$0")
SH_DIR=$(cd -P -- "$(dirname -- "$(readlink -f "$0")")" && pwd -P)
CI_PROJECT_DIR=${CI_PROJECT_DIR-}
git_ref_name () {
local r=$1
local s
s=$(git describe --all "$r" --candidates=0 2>/dev/null | sed "s#^.*/##")
echo "${s:-$(git rev-parse --short "$r")}"
}
proj_name=${CI_PROJECT_DIR##*/}
ref_id=${CI_BUILD_REF-$(git rev-parse HEAD)}
ref_name=${CI_BUILD_REF_NAME-$(git_ref_name HEAD)}
dest_dir=${CI_BUILD_DEST:-dist}
dist_tar_prefix=
bump_file="package.json"
short_refid=$(git rev-parse --short "$ref_id")
def_ci_specs_dir=".ci/" # default ci specs dir => `.ci` (relative project dir)
deploy_cmd="" # cache the deploy command for remote executions
### Helper & ARGS {{{
die () {
[ "${1-}" ] && echo >&2 "fatal: ${1}"
exit "${2-1}"
}
error () {
echo >&2 "Error: ${*}"
}
assert () {
[ -n "$1" ] || die "${2?assert message required}"
}
# cache some parameters forward to `git deploy`
ARGS=()
while [ $# -gt 0 ]; do
argval=${2-}
case "$1" in
--proj-name | -n)
proj_name="$argval"
shift
;;
--bump-file)
bump_file=$argval
shift
;;
--dist-tar-prefix)
# Ensure the prefix path is cleanup (strip tail `/`)
dist_tar_prefix=${argval%/}
shift
;;
-c | --command)
deploy_cmd=$argval
shift
;;
*)
ARGS+=("$(printf '%q' "$1")")
;;
esac
shift
done
# }}}
assert "$proj_name" "project name is required"
WORKDIR=$(mktemp -d)
handle_exit () {
local ec=$?
if [ -d "$WORKDIR" ]; then rm -rf "$WORKDIR"; fi
trap - INT TERM EXIT
# declare -F on_exit, not avaiable in alipine/sh
if type on_exit >/dev/null 2>&1; then on_exit; fi
exit $ec
}
trap handle_exit 0 1 2 3 6 15
# Check the specific refs are same commit
# $1: the reference commit id (full sha1)
is_ref_eq () {
test "$(git merge-base "$@" 2>/dev/null)" = "$1"
}
#
# Build deployment shell source, to be executed in remote `spush -c <CMD>`
#
gen_cd_main () {
local name=./deploy
cat <<-'__CD_MAIN__' | sed "/^ *$/d" >"$name"
#!/bin/sh
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
set -eu
PROG=$(basename "$0")
info () { echo "[${PROG}] ${*}"; }
export CI_DEBUG_TRACE=true
[ "${CI-}" != true ] && exit 1
[ "${CI_DEBUG_TRACE-}" = "true" ] && set -x
ci_dir=${CI_BUILD_SPECS_DIR:-.ci}
resolve_plugin () {
if [ -x "${ci_dir%/}/$1" ]; then
# resolve x file by current .ci specs (for custom cli)
echo ${ci_dir%/}/$p
return 0
elif [ -n "${p#git-ci-plugin*}" ]; then
# ensure suffix: git-ci-plugin-xxx
p="git-ci-plugin-$1"
if [ "$(type -t "$p")" ]; then
echo "$p"
return 0
fi
echo >&2 "error: resolve plugin '$1' failed"
return 127
fi
}
cd_plugins=${CI_DEPLOY_PLUGINS-}
info "Processing CI plugins: ${cd_plugins} ..."
if [ -n "$cd_plugins" ]; then
echo "$cd_plugins" | tr ',' '\n' | while read -r p; do
[ -z "$p" ] && continue
info ">>> stage of '$p'"
cmd=$(resolve_plugin "$p")
info "resolving plugin '$p' => '$cmd'"
if [ "$cmd" != "x${cmd}" ]; then
$cmd
echo
fi
done
else
info "CD plugin list is empty."
fi
__CD_MAIN__
echo $name
}
git_describe () {
# strip serial num
git describe --tags "$1" 2>/dev/null | awk '{sub(/-[0-9]+-g.{7,}/,"");print}'
}
#
# Automate get the build tag and release_tag
#
get_release_tag () {
local ref_id="$1"
local tag=${CI_BUILD_TAG:-"$(git_describe "$ref_id")"}
local suffix="${CI_BUILD_TAG_SUFFIX:-}"
# auto detect tag name
if [ -z "${CI_BUILD_TAG:-}" ]; then
if [[ "${CI_BUILD_REF_NAME}" =~ ^[0-9]+(.[0-9]+)*.[0-9x]+ ]]; then
tag=${CI_BUILD_REF_NAME}
elif [ "${bump_file}" ]; then
# fix closure tag name by bump_file
bump_tag=$(git show "${ref_id}:${bump_file}" | awk -F'"' '/"version": ".+"/{print $4;exit;}') || exit $?
if printf %s "$tag" | grep -Eqv '^v?[0-9]' ||
printf '%s\n%s\n' "$tag" "$bump_tag" | sort -V -C; then
tag=$bump_tag
fi
suffix=${suffix:--preview}
fi
fi
printf '%s' "${tag}${suffix:+${suffix}}"
}
build_dist_tar () {
local in="${1?input dir invalid}"
local of=${2?output file invalid}
if [ -f yarn.lock ]; then
gzip -c yarn.lock > "${in}/yarn.lock.gz"
fi
# Build tar with optional prefix
# NOT use tar --transform because BSD compatible issue
(if [ "$dist_tar_prefix" ]; then
abs_in=$(cd "$in"; pwd)
cd "$WORKDIR"
dirname=$(dirname "$dist_tar_prefix")
if [ "$dirname" != "." ]; then
mkdir -p "$dirname"
fi
ln -sf "$abs_in" "$dist_tar_prefix" \
&& tar -chzf "$of" "$dist_tar_prefix" \
&& rm -rf "$dist_tar_prefix"
else
tar -C "$in" -czf "$of" .
fi)
}
build_tag=$(get_release_tag "$ref_id")
assert "$build_tag" "detect tag failed"
ref_tag="${build_tag}.${short_refid}"
echo "$ref_tag" > "$dest_dir/.version"
# Prepare build stuffs & ENVS
# build tarball of the dest directory `dist`
build_dist_tar "$dest_dir" "$WORKDIR/dist.tgz"
# patch key env vars
export CI_PROJECT_NAME="${CI_PROJECT_NAME:-$proj_name}"
export CI_PROJECT_RELEASE_TAG="$build_tag"
export CI_BUILD_VERSION="$ref_tag"
export CI_BUILD_SPECS_DIR="${CI_BUILD_SPECS_DIR:-${def_ci_specs_dir}}" # relative path
# lock the key env variables by specific patterns,
# for more variables @see https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
env |
grep -E "^(CI_|CD_).*=" |
grep -Ev "^(CI_BUILD_TOKEN|CI_PROJECT_DIR|CI_BUILD_REPO|CI_SERVER)" |
awk -F= '{print $1}' |
sort |
xargs -r -I{} sh -c "typeset -p {} | sed 's#^declare -x ##'" > "$WORKDIR/env"
# sync ci specs dir (is relative to current workdir, eg, .ci)
ci_specs_home="${CI_BUILD_SPECS_DIR%/}"
if [ -d "$ci_specs_home" ]; then
cp -af "$ci_specs_home" "$WORKDIR/"
fi
# Add default rpc commands based on ci specs. (.ci/deploy.sh)
if [ -z "$deploy_cmd" ] && [ "${CI_DEPLOY-}" != "false" ]; then
drpc_sh="$ci_specs_home/deploy.sh"
# add builtin dispatcher based on CD plugins
if [ ! -f "$drpc_sh" ]; then
drpc_sh="$(cd "$WORKDIR" && gen_cd_main)"
echo "Preparing deploy context ... done!"
fi
deploy_cmd="if [ -f \"$drpc_sh\" ]; then sh \"$drpc_sh\"; fi"
fi
# Export and inject context variables for remote commands
ARGS+=('-e "^(CI|CD).*="')
ARGS+=("$(printf -- '--command %q' "$deploy_cmd")")
if [ "${CI_DEBUG_TRACE:-}" = "true" ]; then
ARGS+=('-v')
fi
eval set -- "${ARGS[@]}"
spush -s "${WORKDIR}" -t "/var/ci_build/${proj_name}/${ref_name}/${short_refid}" "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment