mirror of
https://github.com/dokku/dokku.git
synced 2026-02-24 04:00:36 +01:00
It may be desirable to keep the contents of the git directory for the build process. Certain build tools can extract extra information from the .git directory, and some workflows may require that the shipped artifact has the entire source code available locally for later usage.
250 lines
8.8 KiB
Bash
Executable File
250 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
|
|
source "$PLUGIN_AVAILABLE_PATH/apps/functions"
|
|
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
|
set -eo pipefail
|
|
[[ $DOKKU_TRACE ]] && set -x
|
|
|
|
use_git_worktree() {
|
|
declare desc="detects whether to use git worktree"
|
|
local GIT_VERSION MAJOR_VERSION MINOR_VERSION
|
|
|
|
GIT_VERSION=$(git --version | awk '{split($0,a," "); print a[3]}')
|
|
MAJOR_VERSION=$(echo "$GIT_VERSION" | awk '{split($0,a,"."); print a[1]}')
|
|
MINOR_VERSION=$(echo "$GIT_VERSION" | awk '{split($0,a,"."); print a[2]}')
|
|
|
|
if [[ "$MAJOR_VERSION" -ge "3" ]]; then
|
|
return 0
|
|
elif [[ "$MAJOR_VERSION" -eq "2" ]] && [[ "$MINOR_VERSION" -ge "11" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
git_build_app_repo() {
|
|
declare desc="builds local git app repo for app"
|
|
declare APP="$1" REV="$2"
|
|
local DOKKU_GLOBAL_DISABLE_AUTOCREATE
|
|
|
|
verify_app_name "$APP"
|
|
|
|
# clean up after ourselves
|
|
local GIT_BUILD_APP_REPO_TMP_WORK_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
|
|
trap "rm -rf '$GIT_BUILD_APP_REPO_TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT
|
|
|
|
local TMP_TAG="dokku/$REV"
|
|
chmod 755 "$GIT_BUILD_APP_REPO_TMP_WORK_DIR"
|
|
unset GIT_DIR GIT_WORK_TREE
|
|
|
|
! apps_exists "$APP" >/dev/null 2>&1 && apps_maybe_create "$APP"
|
|
|
|
if use_git_worktree; then
|
|
# git worktree - this method uses git worktree which was introduced in git 2.5
|
|
pushd "$DOKKU_ROOT/$APP" >/dev/null
|
|
# unset the git quarantine path to allow us to use 2.13.0+
|
|
# See this issue for more information: https://github.com/dokku/dokku/issues/2796
|
|
suppress_output env -u GIT_QUARANTINE_PATH git worktree add "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV"
|
|
popd >/dev/null 2>&1 || pushd "/tmp" >/dev/null
|
|
pushd "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" >/dev/null
|
|
else
|
|
# git clone - this method creates a new git repository and adds the primary
|
|
# repo as a remote, then does a fetch depth=1 to avoid cloning
|
|
# the entire repo.
|
|
# Not working for git >= 2.11.0 due to changes introduced
|
|
# in this merge:
|
|
# https://github.com/git/git/commit/25ab004c53cdcfea485e5bf437aeaa74df47196d
|
|
pushd "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" >/dev/null
|
|
GIT_DIR="$DOKKU_ROOT/$APP" git tag -d "$TMP_TAG" &>/dev/null || true
|
|
GIT_DIR="$DOKKU_ROOT/$APP" git tag "$TMP_TAG" "$REV" &>/dev/null
|
|
git init &>/dev/null
|
|
git config advice.detachedHead false
|
|
git remote add origin "$DOKKU_ROOT/$APP" &>/dev/null
|
|
git fetch --depth=1 origin "refs/tags/$TMP_TAG" &>/dev/null
|
|
git reset --hard FETCH_HEAD &>/dev/null
|
|
GIT_DIR="$DOKKU_ROOT/$APP" git tag -d "$TMP_TAG" &>/dev/null || true
|
|
fi
|
|
|
|
suppress_output env -u GIT_QUARANTINE_PATH git submodule update --init --recursive
|
|
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
|
|
if [[ "$DOKKU_KEEP_GIT_DIR" != "true" ]]; then
|
|
find . -name .git -prune -exec rm -rf {} \; >/dev/null
|
|
fi
|
|
|
|
if use_git_worktree; then
|
|
pushd "$DOKKU_ROOT/$APP" >/dev/null
|
|
git worktree prune
|
|
popd >/dev/null
|
|
fi
|
|
|
|
local DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_DISABLE_ANSI_PREFIX_REMOVAL
|
|
DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL=$(config_get "$APP" DOKKU_DISABLE_ANSI_PREFIX_REMOVAL || true)
|
|
DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL=$(config_get --global DOKKU_DISABLE_ANSI_PREFIX_REMOVAL || true)
|
|
DOKKU_DISABLE_ANSI_PREFIX_REMOVAL=${DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL:="$DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL"}
|
|
|
|
if [[ "$DOKKU_DISABLE_ANSI_PREFIX_REMOVAL" == "true" ]]; then
|
|
git_trigger_build "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV"
|
|
else
|
|
git_trigger_build "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV" | sed -u "s/^/"$'\e[1G'"/"
|
|
fi
|
|
}
|
|
|
|
git_trigger_build() {
|
|
declare desc="triggers the actual build process for a given app within a directory at a particular revision"
|
|
declare APP="$1" TMP_WORK_DIR="$2" REV="$3"
|
|
|
|
plugn trigger post-extract "$APP" "$TMP_WORK_DIR" "$REV"
|
|
if [[ -f Dockerfile ]] && [[ "$(
|
|
[[ -f .env ]] && grep -q BUILDPACK_URL .env
|
|
echo $?
|
|
)" != "0" ]] && [[ ! -f ".buildpacks" ]] && [[ -z $(config_get "$APP" BUILDPACK_URL || true) ]]; then
|
|
plugn trigger pre-receive-app "$APP" "dockerfile" "$TMP_WORK_DIR" "$REV"
|
|
dokku_receive "$APP" "dockerfile" "$TMP_WORK_DIR"
|
|
else
|
|
plugn trigger pre-receive-app "$APP" "herokuish" "$TMP_WORK_DIR" "$REV"
|
|
dokku_receive "$APP" "herokuish" "$TMP_WORK_DIR"
|
|
fi
|
|
}
|
|
|
|
git_deploy_branch() {
|
|
declare desc="retrieve the deploy branch for a given application"
|
|
local cmd="git-hook"
|
|
local APP="$1"
|
|
|
|
local DOKKU_DEPLOY_BRANCH="$(fn-plugin-property-get "git" "$APP" "deploy-branch" "")"
|
|
local DOKKU_GLOBAL_DEPLOY_BRANCH="$(fn-plugin-property-get "git" "--global" "deploy-branch" "")"
|
|
if [[ -n "$DOKKU_DEPLOY_BRANCH" ]]; then
|
|
echo "$DOKKU_DEPLOY_BRANCH"
|
|
elif [[ -n "$DOKKU_GLOBAL_DEPLOY_BRANCH" ]]; then
|
|
echo "$DOKKU_GLOBAL_DEPLOY_BRANCH"
|
|
else
|
|
echo "master"
|
|
fi
|
|
}
|
|
|
|
git_hook_cmd() {
|
|
declare desc="kick off receive-app trigger from git prereceive hook"
|
|
local cmd="git-hook"
|
|
local APP="$2"
|
|
local DOKKU_DEPLOY_BRANCH
|
|
is_valid_app_name "$APP"
|
|
|
|
DOKKU_DEPLOY_BRANCH="$(git_deploy_branch "$APP")"
|
|
if ! git check-ref-format --branch "$DOKKU_DEPLOY_BRANCH" >/dev/null 2>&1; then
|
|
echo $'\e[1G\e[K'"-----> WARNING: Invalid branch name '$DOKKU_DEPLOY_BRANCH' specified via DOKKU_DEPLOY_BRANCH."
|
|
echo $'\e[1G\e[K'"-----> For more details, please see the man page for 'git-check-ref-format.'"
|
|
return
|
|
fi
|
|
|
|
local oldrev newrev refname
|
|
while read -r oldrev newrev refname; do
|
|
# Only run this script for the master branch. You can remove this
|
|
# if block if you wish to run it for others as well.
|
|
if [[ $refname == "refs/heads/${DOKKU_DEPLOY_BRANCH}" ]]; then
|
|
# broken out into plugin so we might support other methods to receive an app
|
|
# shellcheck disable=SC2086
|
|
git_receive_app "$APP" "$newrev"
|
|
else
|
|
if [[ $(find "$PLUGIN_PATH"/enabled/*/receive-branch 2>/dev/null | wc -l) != 1 ]]; then
|
|
# shellcheck disable=SC2086
|
|
plugn trigger receive-branch $APP $newrev $refname
|
|
else
|
|
echo $'\e[1G\e[K'"-----> WARNING: deploy did not complete, you must push to ${DOKKU_DEPLOY_BRANCH}."
|
|
echo $'\e[1G\e[K'"-----> for example, try 'git push <dokku> ${refname/refs\/heads\//}:${DOKKU_DEPLOY_BRANCH}'"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
git_build() {
|
|
declare desc="setup and call git_build_app_repo"
|
|
local APP="$1" REV="$2"
|
|
local DOKKU_DEPLOY_BRANCH ENV_VAR_NAME REF
|
|
if [[ $# -ge 2 ]]; then
|
|
ENV_VAR_NAME="$(fn-plugin-property-get "git" "$APP" "rev-env-var")"
|
|
if [[ -z "$ENV_VAR_NAME" ]] && ! fn-plugin-property-exists "git" "$APP" "rev-env-var"; then
|
|
ENV_VAR_NAME="GIT_REV"
|
|
fi
|
|
|
|
if [[ -n "$ENV_VAR_NAME" ]]; then
|
|
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" "${ENV_VAR_NAME}=${REV}"
|
|
fi
|
|
local REF="$REV"
|
|
else
|
|
DOKKU_DEPLOY_BRANCH="$(git_deploy_branch "$APP")"
|
|
REF=$(<"$DOKKU_ROOT/$APP/refs/heads/$DOKKU_DEPLOY_BRANCH")
|
|
fi
|
|
|
|
# shellcheck disable=SC2086
|
|
git_build_app_repo $APP $REF
|
|
}
|
|
|
|
git_receive_app() {
|
|
declare desc="git receive-app plugin trigger"
|
|
declare APP="$1" REV="$2"
|
|
|
|
# Don't trigger git build if there is no git repository.
|
|
if [[ ! -d "$DOKKU_ROOT/$APP/refs" ]]; then
|
|
true
|
|
else
|
|
acquire_app_deploy_lock "$APP" "exclusive"
|
|
# shellcheck disable=SC2086
|
|
git_build $APP $REV
|
|
release_app_deploy_lock "$APP"
|
|
fi
|
|
}
|
|
|
|
git_upload_pack_cmd() {
|
|
declare desc="executes git-upload-pack"
|
|
declare cmd="git-upload-pack"
|
|
declare APP="$2"
|
|
APP="$(echo "$APP" | perl -pe 's/(?<!\\)'\''//g' | sed 's/\\'\''/'\''/g' | sed 's/^\///g')"
|
|
is_valid_app_name "$APP"
|
|
! apps_exists "$APP" >/dev/null 2>&1 && apps_maybe_create "$APP"
|
|
|
|
plugn trigger git-pre-pull "$APP"
|
|
cat | git-upload-pack "$DOKKU_ROOT/$APP"
|
|
plugn trigger git-post-pull "$APP"
|
|
}
|
|
|
|
git_glob_cmd() {
|
|
declare desc="catch-all for any other git-* commands"
|
|
local cmd="git-*"
|
|
local APP="$(echo "$2" | perl -pe 's/(?<!\\)'\''//g' | sed 's/\\'\''/'\''/g' | sed 's/^\///g')"
|
|
local APP_PATH=$DOKKU_ROOT/$APP
|
|
is_valid_app_name "$APP"
|
|
|
|
if [[ $1 == "git-receive-pack" && ! -d "$APP_PATH/refs" ]]; then
|
|
! apps_exists "$APP" >/dev/null 2>&1 && apps_maybe_create "$APP"
|
|
|
|
fn-git-create-hook "$APP"
|
|
fi
|
|
|
|
if [[ $1 == "git-receive-pack" ]]; then
|
|
local args="$1 '$APP_PATH'"
|
|
else
|
|
local args=$*
|
|
fi
|
|
git-shell -c "$args"
|
|
}
|
|
|
|
fn-git-create-hook() {
|
|
declare APP="$1"
|
|
local APP_PATH="$DOKKU_ROOT/$APP"
|
|
local PRERECEIVE_HOOK="$APP_PATH/hooks/pre-receive"
|
|
verify_app_name "$APP"
|
|
|
|
if [[ ! -d "$APP_PATH/refs" ]]; then
|
|
git init --bare "$APP_PATH" >/dev/null
|
|
fi
|
|
|
|
cat >"$PRERECEIVE_HOOK" <<EOF
|
|
#!/usr/bin/env bash
|
|
set -e; set -o pipefail;
|
|
|
|
cat | DOKKU_ROOT="$DOKKU_ROOT" dokku git-hook $APP
|
|
EOF
|
|
chmod +x "$PRERECEIVE_HOOK"
|
|
}
|