#!/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" source "$PLUGIN_AVAILABLE_PATH/git/internal-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 ! plugn trigger app-exists "$APP" >/dev/null 2>&1 && plugn trigger app-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" declare APP="$1" declare deprecated=true dokku_log_warn "Deprecated: plugn#git-deploy-branch" fn-git-deploy-branch "$APP" } cmd-git-hook() { declare desc="kick off receive-app trigger from git prereceive hook" declare cmd="git-hook" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" local DOKKU_DEPLOY_BRANCH is_valid_app_name "$APP" DOKKU_DEPLOY_BRANCH="$(fn-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 ${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="$(fn-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 } cmd-git-upload-pack() { declare desc="executes git-upload-pack" declare cmd="git-upload-pack" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" APP="$(echo "$APP" | perl -pe 's/(?/dev/null 2>&1 && plugn trigger app-maybe-create "$APP" plugn trigger git-pre-pull "$APP" cat | git-upload-pack "$DOKKU_ROOT/$APP" plugn trigger git-post-pull "$APP" } cmd-git-glob() { declare desc="catch-all for any other git-* commands" declare cmd="git-*" local APP="$(echo "$2" | perl -pe 's/(?/dev/null 2>&1 && plugn trigger app-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" <