Files
dokku/plugins/git/internal-functions
Jose Diaz-Gonzalez 6eb8b8632c fix: enforce 0600 permissions on .netrc credentials file
The previous use of `touch` before `netrc set` allowed the file to inherit the umask and be world-readable, exposing stored git credentials to local users. The set and unset paths now explicitly chmod 0600 and chown to the dokku user, and the plugin install hook repairs permissions on already-affected installations.
2026-05-09 12:22:17 -04:00

678 lines
20 KiB
Bash
Executable File

#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-git-allow-host() {
declare desc="adds a host to known_hosts"
local cmd="git:allow-host"
[[ "$1" == "$cmd" ]] && shift 1
declare HOST="$1"
[[ -z "$HOST" ]] && dokku_log_fail "Please supply a git host"
ssh-keyscan -t rsa "$HOST" >>"$DOKKU_ROOT/.ssh/known_hosts"
dokku_log_info1 "$HOST added to known hosts"
}
cmd-git-from-archive() {
declare desc="updates an app's git repository with a given archive file"
local cmd="git:from-archive"
[[ "$1" == "$cmd" ]] && shift 1
declare APP ARCHIVE_URL USER_NAME USER_EMAIL
local ARCHIVE_TYPE="tar"
ARGS=()
skip=false
for arg in "$@"; do
if [[ "$arg" == "--archive-type" ]]; then
skip=true
continue
fi
if [[ "$skip" == "true" ]]; then
ARCHIVE_TYPE="$arg"
skip=false
continue
fi
ARGS+=("$arg")
done
APP="${ARGS[0]}"
ARCHIVE_URL="${ARGS[1]}"
USER_NAME="${ARGS[2]}"
USER_EMAIL="${ARGS[3]}"
verify_app_name "$APP"
[[ -z "$ARCHIVE_URL" ]] && dokku_log_fail "Please specify an archive url or -- to fetch the archive from stdin"
local VALID_ARCHIVE_TYPES=("tar" "tar.gz" "zip")
if ! fn-in-array "$ARCHIVE_TYPE" "${ARCHIVE_TYPE[@]}"; then
dokku_log_fail "Invalid archive type specified, valid archive types include: tar, tar.gz, zip"
fi
dokku_setup_build_capture "$APP" "git:from-archive"
plugn trigger git-from-archive "$APP" "$ARCHIVE_URL" "$ARCHIVE_TYPE" "$USER_NAME" "$USER_EMAIL"
plugn trigger deploy-source-set "$APP" "$ARCHIVE_TYPE" "$ARCHIVE_URL"
}
cmd-git-generate-deploy-key() {
declare desc="generates a deploy ssh key"
local cmd="git:generate-deploy-key"
[[ "$1" == "$cmd" ]] && shift 1
if [[ -f "$DOKKU_ROOT/.ssh/id_ed25519.pub" ]] || [[ -f "$DOKKU_ROOT/.ssh/id_rsa.pub" ]]; then
dokku_log_exclaim_quiet "A deploy key already exists for this host"
return
fi
ssh-keygen -t ed25519 -C "dokku@$(hostname)" -N "" -f "$DOKKU_ROOT/.ssh/id_ed25519"
}
cmd-git-auth() {
declare desc="configures netrc authentication for a given git server"
local cmd="git:auth"
[[ "$1" == "$cmd" ]] && shift 1
declare HOST="$1" USERNAME="$2" PASSWORD="$3"
[[ -z "$HOST" ]] && dokku_log_fail "Please supply a git host"
PASSWORD="$(fn-git-auth-read-password "$USERNAME" "$PASSWORD")"
if [[ -n "$USERNAME" ]] && [[ -z "$PASSWORD" ]]; then
dokku_log_fail "Missing password for netrc auth entry"
fi
if [[ -z "$USERNAME" ]]; then
dokku_log_info1 "Removing netrc auth entry for host $HOST"
netrc unset "$HOST"
local exit_code=$?
fn-git-auth-secure-netrc
return $exit_code
fi
dokku_log_info1 "Setting netrc auth entry for host $HOST"
netrc set "$HOST" "$USERNAME" "$PASSWORD"
fn-git-auth-secure-netrc
}
fn-git-auth-secure-netrc() {
declare desc="enforces 0600 permissions and dokku ownership on the netrc file"
[[ ! -f "${DOKKU_ROOT}/.netrc" ]] && return 0
chmod 600 "${DOKKU_ROOT}/.netrc"
chown "${DOKKU_SYSTEM_USER:-dokku}:${DOKKU_SYSTEM_GROUP:-dokku}" "${DOKKU_ROOT}/.netrc"
}
cmd-git-auth-status() {
declare desc="reports whether netrc authentication matches the requested state"
local cmd="git:auth-status"
[[ "$1" == "$cmd" ]] && shift 1
declare HOST="$1" USERNAME="$2" PASSWORD="$3"
[[ -z "$HOST" ]] && dokku_log_fail "Please supply a git host"
PASSWORD="$(fn-git-auth-read-password "$USERNAME" "$PASSWORD")"
if [[ -n "$USERNAME" ]] && [[ -z "$PASSWORD" ]]; then
dokku_log_fail "Missing password for netrc auth entry"
fi
local current
current="$(netrc get "$HOST" 2>/dev/null)" || current=""
if [[ -z "$USERNAME" ]]; then
[[ -z "$current" ]] && return 0
return 1
fi
[[ "$current" == "${USERNAME}:${PASSWORD}" ]] && return 0
return 1
}
fn-git-auth-read-password() {
declare desc="reads a netrc password from stdin when not provided as an argument"
declare USERNAME="$1" PASSWORD="$2"
if [[ -n "$USERNAME" ]] && [[ -z "$PASSWORD" ]] && [[ -p /dev/stdin ]]; then
IFS= read -r PASSWORD || true
fi
echo -n "$PASSWORD"
}
cmd-git-load-image() {
declare desc="updates an app's git repository with a docker image loaded from stdin"
local cmd="git:load-image"
[[ "$1" == "$cmd" ]] && shift 1
declare APP DOCKER_IMAGE USER_NAME USER_EMAIL
local BUILD_DIR
ARGS=()
skip=false
for arg in "$@"; do
if [[ "$arg" == "--build-dir" ]]; then
skip=true
continue
fi
if [[ "$skip" == "true" ]]; then
BUILD_DIR="$arg"
skip=false
continue
fi
ARGS+=("$arg")
done
APP="${ARGS[0]}"
DOCKER_IMAGE="${ARGS[1]}"
USER_NAME="${ARGS[2]}"
USER_EMAIL="${ARGS[3]}"
verify_app_name "$APP"
[[ -z "$DOCKER_IMAGE" ]] && dokku_log_fail "Please specify a docker image"
[[ ! -t 0 ]] || dokku_log_fail "Expecting tar archive containing docker image on STDIN"
dokku_setup_build_capture "$APP" "git:load-image"
cat | docker load
if ! verify_image "$DOCKER_IMAGE"; then
dokku_log_fail "Loaded image tarball but the specified docker image was not found: $DOCKER_IMAGE"
fi
if ! plugn trigger git-from-image "$APP" "$DOCKER_IMAGE" "$BUILD_DIR" "$USER_NAME" "$USER_EMAIL"; then
return 1
fi
plugn trigger deploy-source-set "$APP" "docker-image" "$DOCKER_IMAGE"
}
cmd-git-from-image() {
declare desc="updates an app's git repository with a given docker image"
local cmd="git:from-image"
[[ "$1" == "$cmd" ]] && shift 1
declare APP DOCKER_IMAGE USER_NAME USER_EMAIL
local BUILD_DIR FORCE=false
ARGS=()
skip=false
for arg in "$@"; do
if [[ "$arg" == "--build-dir" ]]; then
skip=true
continue
fi
if [[ "$arg" == "--force" ]]; then
FORCE=true
continue
fi
if [[ "$skip" == "true" ]]; then
BUILD_DIR="$arg"
skip=false
continue
fi
ARGS+=("$arg")
done
APP="${ARGS[0]}"
DOCKER_IMAGE="${ARGS[1]}"
USER_NAME="${ARGS[2]}"
USER_EMAIL="${ARGS[3]}"
verify_app_name "$APP"
[[ -z "$DOCKER_IMAGE" ]] && dokku_log_fail "Please specify a docker image"
if [[ "$FORCE" == "true" ]]; then
export DOKKU_APPS_FORCE_DELETE=1
fi
dokku_setup_build_capture "$APP" "git:from-image"
if ! plugn trigger git-from-image "$APP" "$DOCKER_IMAGE" "$BUILD_DIR" "$USER_NAME" "$USER_EMAIL"; then
return 1
fi
plugn trigger deploy-source-set "$APP" "docker-image" "$DOCKER_IMAGE"
}
cmd-git-sync() {
declare desc="clone or fetch an app from remote git repo"
local cmd="git:sync"
[[ "$1" == "$cmd" ]] && shift 1
declare APP GIT_REMOTE GIT_REF FLAG
local CURRENT_REF DOKKU_DEPLOY_BRANCH SHOULD_BUILD SKIP_DEPLOY_BRANCH UPDATED_REF
ARGS=()
for arg in "$@"; do
if [[ "$arg" == "--build" ]]; then
FLAG="--build"
continue
fi
if [[ "$arg" == "--build-if-changes" ]]; then
FLAG="--build-if-changes"
continue
fi
if [[ "$arg" == "--skip-deploy-branch" ]]; then
SKIP_DEPLOY_BRANCH="true"
continue
fi
ARGS+=("$arg")
done
APP="${ARGS[0]}"
GIT_REMOTE="${ARGS[1]}"
GIT_REF="${ARGS[2]}"
verify_app_name "$APP"
if [[ -z "$GIT_REMOTE" ]]; then
dokku_log_fail "Missing GIT_REMOTE parameter"
return
fi
local APP_ROOT="$DOKKU_ROOT/$APP"
DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
CURRENT_REF="$(fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true)"
dokku_setup_build_capture "$APP" "git:sync"
if ! fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" &>/dev/null; then
dokku_log_info1_quiet "Cloning $APP from $GIT_REMOTE#$GIT_REF"
fn-git-clone "$APP" "$GIT_REMOTE" "$GIT_REF" "$SKIP_DEPLOY_BRANCH"
else
dokku_log_verbose "Fetching remote code for $APP from $GIT_REMOTE#$GIT_REF"
fn-git-fetch "$APP" "$GIT_REMOTE" "$GIT_REF"
fi
UPDATED_REF="$(fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true)"
local SHOULD_BUILD=false
if [[ "$FLAG" == "--build" ]]; then
SHOULD_BUILD=true
elif [[ "$FLAG" == "--build-if-changes" ]]; then
if [[ "$CURRENT_REF" == "$UPDATED_REF" ]]; then
dokku_log_verbose "Skipping build as no changes were detected"
return
fi
SHOULD_BUILD=true
fi
if [[ "$SHOULD_BUILD" == "true" ]]; then
if [[ -n "$GIT_REF" ]]; then
GIT_REF="$(fn-git-cmd "$APP_ROOT" rev-parse "$GIT_REF")"
else
GIT_REF="$UPDATED_REF"
fi
plugn trigger receive-app "$APP" "$GIT_REF"
plugn trigger deploy-source-set "$APP" "git-sync" "${GIT_REMOTE}#${GIT_REF}"
fi
}
cmd-git-public-key() {
declare desc="outputs the dokku public deploy key"
local cmd="git:public-key"
[[ "$1" == "$cmd" ]] && shift 1
if [[ -f "$DOKKU_ROOT/.ssh/id_ed25519.pub" ]]; then
cat "$DOKKU_ROOT/.ssh/id_ed25519.pub"
return
elif [[ -f "$DOKKU_ROOT/.ssh/id_rsa.pub" ]]; then
cat "$DOKKU_ROOT/.ssh/id_rsa.pub"
return
fi
fn-git-auth-error
}
cmd-git-report() {
declare desc="displays a git report for one or more apps"
declare cmd="git:report"
[[ "$1" == "$cmd" ]] && shift 1
fn-report-parse-args "$@"
set -- "${REPORT_ARGS[@]}"
declare APP="${1:-}" INFO_FLAG="${2:-}"
if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then
INFO_FLAG="$APP"
APP=""
fi
if [[ "$REPORT_IS_GLOBAL" == "true" ]]; then
APP="--global"
fi
if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then
INFO_FLAG="true"
fi
if [[ "$APP" == "--global" ]]; then
cmd-git-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT"
elif [[ -z "$APP" ]]; then
for app in $(dokku_apps); do
cmd-git-report-single "$app" "$INFO_FLAG" "$REPORT_FORMAT" | tee || true
done
else
cmd-git-report-single "$APP" "$INFO_FLAG" "$REPORT_FORMAT"
fi
}
cmd-git-report-single() {
declare APP="$1" INFO_FLAG="$2" FORMAT="${3:-stdout}"
local APP_ROOT="$DOKKU_ROOT/$APP"
if [[ "$INFO_FLAG" == "true" ]]; then
INFO_FLAG=""
fi
local flag_map=()
if [[ "$APP" == "--global" ]]; then
flag_map=(
"--git-global-deploy-branch: $(fn-plugin-property-get "git" "--global" "deploy-branch" "master")"
)
else
verify_app_name "$APP"
flag_map=(
"--git-deploy-branch: $(fn-plugin-property-get "git" "$APP" "deploy-branch" "master")"
"--git-global-deploy-branch: $(fn-plugin-property-get "git" "--global" "deploy-branch" "master")"
"--git-keep-git-dir: $(fn-plugin-property-get "git" "$APP" "keep-git-dir" "false")"
"--git-rev-env-var: $(fn-plugin-property-get "git" "$APP" "rev-env-var" "GIT_REV")"
"--git-sha: $(fn-git-cmd "$APP_ROOT" rev-parse HEAD 2>/dev/null || false)"
"--git-source-image: $(fn-git-source-image "$APP")"
"--git-last-updated-at: $(fn-git-last-updated-at "$APP")"
)
fi
fn-report-validate-format "$FORMAT" "$INFO_FLAG"
if [[ "$FORMAT" == "json" ]]; then
fn-report-emit-json flag_map "git"
return
fi
if [[ -z "$INFO_FLAG" ]]; then
if [[ "$APP" == "--global" ]]; then
dokku_log_info2_quiet "global git information"
else
dokku_log_info2_quiet "${APP} git information"
fi
for flag in "${flag_map[@]}"; do
key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')"
dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")"
done
else
local match=false
local value_exists=false
for flag in "${flag_map[@]}"; do
valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)"
if [[ "$flag" == "${INFO_FLAG}:"* ]]; then
value=${flag#*: }
size="${#value}"
if [[ "$size" -ne 0 ]]; then
echo "$value" && match=true && value_exists=true
else
match=true
fi
fi
done
[[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}"
[[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed"
fi
}
cmd-git-status() {
declare desc="check the git status output for an app"
local cmd="git:status"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1"
local APP_ROOT="$DOKKU_ROOT/$APP"
verify_app_name "$APP"
fn-git-cmd "$APP_ROOT" status
}
fn-git-auth-error() {
dokku_log_warn "There is no deploy key associated with the $DOKKU_SYSTEM_USER user."
dokku_log_warn "Generate an ssh key with the following command:"
dokku_log_warn " dokku git:generate-deploy-key"
dokku_log_fail "As an alternative, configure the netrc authentication via the git:auth command"
}
fn-git-remove-clone-folder() {
declare APP_CLONE_ROOT="$1"
dokku_log_info1 "About to delete $APP_CLONE_ROOT"
rm -rf "$APP_CLONE_ROOT"
dokku_log_info1 "Successfully deleted $APP_CLONE_ROOT"
}
fn-git-create-hook() {
declare APP="$1"
local APP_PATH="$DOKKU_ROOT/$APP"
local PRERECEIVE_HOOK="$APP_PATH/hooks/pre-receive"
if [[ ! -d "$APP_PATH/refs" ]]; then
suppress_output git init -q --bare "$APP_PATH"
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"
}
fn-git-clone() {
declare desc="creates an app from remote git repo"
declare APP="$1" GIT_REMOTE="$2" GIT_REF="$3" SKIP_DEPLOY_BRANCH="$4"
local APP_ROOT="$DOKKU_ROOT/$APP"
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
if fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" &>/dev/null; then
dokku_log_fail "The clone subcommand can only be executed for new applications"
fi
if [[ -z "$GIT_REF" ]]; then
GIT_REF="$(fn-git-deploy-branch "$APP")"
fi
local TMP_IS_REF_DIR=$(mktemp -d "/tmp/dokku-ref-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
trap "rm -rf '$TMP_IS_REF_DIR' >/dev/null" RETURN INT TERM EXIT
is_ref=true
if GIT_TERMINAL_PROMPT=0 git clone --depth 1 -n --branch "$GIT_REF" "$GIT_REMOTE" "$TMP_IS_REF_DIR" 2>/dev/null; then
is_ref=false
fi
rm -rf "$TMP_IS_REF_DIR"
local TMP_CLONE_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
trap "rm -rf '$TMP_CLONE_DIR' >/dev/null" RETURN INT TERM EXIT
if [[ "$is_ref" == "true" ]]; then
GIT_TERMINAL_PROMPT=0 suppress_output git clone -n "$GIT_REMOTE" "$TMP_CLONE_DIR"
fn-git-cmd "$TMP_CLONE_DIR" checkout -qq "$GIT_REF"
else
GIT_TERMINAL_PROMPT=0 suppress_output git clone -n --branch "$GIT_REF" "$GIT_REMOTE" "$TMP_CLONE_DIR"
if fn-git-cmd "$TMP_CLONE_DIR" show-ref --verify "refs/heads/$GIT_REF" &>/dev/null; then
if [[ "$SKIP_DEPLOY_BRANCH" != "true" ]]; then
dokku_log_verbose "Detected branch, setting deploy-branch to $GIT_REF"
fn-plugin-property-write "git" "$APP" "deploy-branch" "$GIT_REF"
else
dokku_log_verbose "Detected branch $GIT_REF, skipping deploy-branch setting"
fi
fi
fi
DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
if [[ "$GIT_REF" != "$DOKKU_DEPLOY_BRANCH" ]]; then
if [[ "$is_ref" == "true" ]]; then
fn-git-cmd "$TMP_CLONE_DIR" branch -qq -D "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true
fi
fn-git-cmd "$TMP_CLONE_DIR" checkout -qq -b "$DOKKU_DEPLOY_BRANCH"
fi
rsync -a "$TMP_CLONE_DIR/.git/" "$APP_ROOT"
fn-git-create-hook "$APP"
fn-git-cmd "$APP_ROOT" config --add core.bare true
}
fn-git-cmd() {
declare GIT_DIR="$1"
local exit_code="1"
shift 1
pushd "$GIT_DIR" >/dev/null
git "$@"
exit_code="$?"
popd &>/dev/null || pushd "/tmp" >/dev/null
return $exit_code
}
fn-git-fetch() {
declare APP="$1" GIT_REMOTE="$2" GIT_REF="$3"
local DOKKU_DEPLOY_BRANCH
local APP_ROOT="$DOKKU_ROOT/$APP"
local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
if ! fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" &>/dev/null; then
dokku_log_fail "The fetch subcommand can only be executed for existing applications"
fi
DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
if ! fn-git-cmd "$APP_ROOT" check-ref-format --branch "$DOKKU_DEPLOY_BRANCH" &>/dev/null; then
dokku_log_warn "Invalid branch name '$DOKKU_DEPLOY_BRANCH' specified via deploy-branch setting."
dokku_log_warn "For more details, please see the man page for 'git-check-ref-format.'"
return
fi
fn-git-cmd "$APP_ROOT" remote rm remote &>/dev/null || true
fn-git-cmd "$APP_ROOT" remote add --mirror=fetch --no-tags remote "$GIT_REMOTE"
if [[ -z "$GIT_REF" ]]; then
GIT_TERMINAL_PROMPT=0 fn-git-cmd "$APP_ROOT" fetch --update-head-ok remote "$DOKKU_DEPLOY_BRANCH"
else
GIT_TERMINAL_PROMPT=0 fn-git-cmd "$APP_ROOT" fetch --update-head-ok remote
fn-git-cmd "$APP_ROOT" update-ref "refs/heads/$DOKKU_DEPLOY_BRANCH" "$GIT_REF^{commit}"
fi
fn-git-cmd "$APP_ROOT" config --add core.bare true
}
fn-git-has-code() {
declare desc="checks if there is code at a specific branch"
declare APP="$1" DOKKU_DEPLOY_BRANCH="$2"
if [[ -z "$DOKKU_DEPLOY_BRANCH" ]]; then
DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
fi
local HEAD_FILE="$DOKKU_ROOT/$APP/refs/heads/$DOKKU_DEPLOY_BRANCH"
if [[ -f "$HEAD_FILE" ]]; then
return 0
fi
return 1
}
fn-git-last-updated-at() {
declare desc="retrieve the deploy branch for a given application"
declare APP="$1"
local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
local HEAD_FILE="$DOKKU_ROOT/$APP/refs/heads/$DOKKU_DEPLOY_BRANCH"
if [[ -f "$HEAD_FILE" ]]; then
stat -c %Y "$HEAD_FILE"
fi
}
fn-git-deploy-branch() {
declare desc="retrieve the deploy branch for a given application"
local APP="$1"
local DEFAULT_BRANCH="${2-master}"
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 "$DEFAULT_BRANCH"
fi
}
fn-git-setup-build-dir() {
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
if [[ "$DOKKU_KEEP_GIT_DIR" == "true" ]]; then
fn-git-setup-build-dir-new "$APP" "$GIT_WORKDIR" "$REV"
else
fn-git-setup-build-dir-worktree "$APP" "$GIT_WORKDIR" "$REV"
fi
}
fn-git-setup-build-dir-new() {
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
local APP_ROOT="$DOKKU_ROOT/$APP"
local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
# 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
unset GIT_QUARANTINE_PATH
# repo workaround from https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52249
# and https://docs.gitlab.com/ee/user/project/repository/repository_mirroring.html#preventing-conflicts-using-a-pre-receive-hook
fn-git-cmd "$APP_ROOT" archive "$REV" | tar x --warning=none -C "${GIT_WORKDIR}"
suppress_output fn-git-cmd "$GIT_WORKDIR" clone --bare "$DOKKU_ROOT/$APP" .git
suppress_output fn-git-cmd "$GIT_WORKDIR" config --local gc.auto 0
suppress_output fn-git-cmd "$GIT_WORKDIR" config --local --bool core.bare false
suppress_output fn-git-cmd "$GIT_WORKDIR" config --local receive.denyCurrentBranch ignore
suppress_output fn-git-cmd "$GIT_WORKDIR" symbolic-ref HEAD "refs/heads/$DOKKU_DEPLOY_BRANCH"
suppress_output fn-git-cmd "$GIT_WORKDIR" reset "$REV" -- .
suppress_output fn-git-cmd "$GIT_WORKDIR" push $GIT_WORKDIR $REV:refs/heads/$DOKKU_DEPLOY_BRANCH
fn-git-setup-build-dir-submodules "$APP" "$GIT_WORKDIR"
}
fn-git-setup-build-dir-worktree() {
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
local APP_ROOT="$DOKKU_ROOT/$APP"
# 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
unset GIT_QUARANTINE_PATH
suppress_output fn-git-cmd "$APP_ROOT" worktree add "$GIT_WORKDIR" "$REV"
fn-git-setup-build-dir-submodules "$APP" "$GIT_WORKDIR"
suppress_output fn-git-cmd "$APP_ROOT" worktree prune
}
fn-git-setup-build-dir-submodules() {
declare APP="$1" GIT_WORKDIR="$2"
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
# 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
unset GIT_QUARANTINE_PATH
suppress_output fn-git-cmd "$GIT_WORKDIR" submodule sync --recursive
suppress_output fn-git-cmd "$GIT_WORKDIR" submodule update --init --recursive
if [[ "$DOKKU_KEEP_GIT_DIR" != "true" ]]; then
pushd "$GIT_WORKDIR" >/dev/null
find "$GIT_WORKDIR" -name .git -prune -exec rm -rf {} \; >/dev/null
popd &>/dev/null || pushd "/tmp" >/dev/null
fi
}
fn-git-source-image() {
declare desc="retrieve the source-image for a given application"
declare APP="$1"
fn-plugin-property-get "git" "$APP" "source-image" ""
}