#!/usr/bin/env bash set -euo pipefail SOURCE_BRANCH="${SOURCE_BRANCH:-master}" COMMIT_HASH="${COMMIT_HASH:-}" GIT_REMOTE_URL="${GIT_REMOTE_URL:-}" GIT_REMOTE_FALLBACK_URL="${GIT_REMOTE_FALLBACK_URL:-}" SOURCE_COMMIT_FILE="${SOURCE_COMMIT_FILE:-.jenkins-source-commit}" # Windows PowerShell 5.1 的 UTF-8 输出可能带 BOM;下游参数校验前先剥离不可见字节。 SOURCE_BRANCH="$(printf "%s" "${SOURCE_BRANCH}" | sed $'s/^\xef\xbb\xbf//' | tr -d '\r\n')" COMMIT_HASH="$(printf "%s" "${COMMIT_HASH}" | sed $'s/^\xef\xbb\xbf//' | tr -d '\r\n')" GIT_REMOTE_URL="$(printf "%s" "${GIT_REMOTE_URL}" | sed $'s/^\xef\xbb\xbf//' | tr -d '\r\n')" GIT_REMOTE_FALLBACK_URL="$(printf "%s" "${GIT_REMOTE_FALLBACK_URL}" | sed $'s/^\xef\xbb\xbf//' | tr -d '\r\n')" if [[ ! "${SOURCE_BRANCH}" =~ ^[0-9A-Za-z._/-]+$ ]]; then echo "[jenkins-checkout-source] SOURCE_BRANCH 只能包含数字、字母、点、下划线、短横线和斜杠: ${SOURCE_BRANCH}" >&2 exit 1 fi if [[ "${SOURCE_BRANCH}" == /* || "${SOURCE_BRANCH}" == */ || "${SOURCE_BRANCH}" == *..* ]]; then echo "[jenkins-checkout-source] SOURCE_BRANCH 不能以斜杠开头/结尾,也不能包含连续点号: ${SOURCE_BRANCH}" >&2 exit 1 fi if [[ -n "${COMMIT_HASH}" && ! "${COMMIT_HASH}" =~ ^[0-9a-fA-F]{7,40}$ ]]; then echo "[jenkins-checkout-source] COMMIT_HASH 只能填写 7 到 40 位十六进制 Git commit hash: ${COMMIT_HASH}" >&2 exit 1 fi GIT_REMOTE_CANDIDATES=() add_git_remote_candidate() { local candidate="$1" local existing if [[ -z "${candidate}" ]]; then return fi for existing in "${GIT_REMOTE_CANDIDATES[@]}"; do if [[ "${existing}" == "${candidate}" ]]; then return fi done GIT_REMOTE_CANDIDATES+=("${candidate}") } fetch_source_branch() { local remote_url="$1" if [[ -n "${remote_url}" ]]; then git remote set-url origin "${remote_url}" fi echo "[jenkins-checkout-source] 尝试 Git 远端: ${remote_url:-origin}" if [[ -z "${COMMIT_HASH}" ]]; then git fetch --no-tags --prune --depth=1 origin "+refs/heads/${SOURCE_BRANCH}:refs/remotes/origin/${SOURCE_BRANCH}" else git fetch --no-tags --prune origin "+refs/heads/${SOURCE_BRANCH}:refs/remotes/origin/${SOURCE_BRANCH}" fi } add_git_remote_candidate "${GIT_REMOTE_URL}" add_git_remote_candidate "${GIT_REMOTE_FALLBACK_URL}" git reset --hard HEAD if [[ "${#GIT_REMOTE_CANDIDATES[@]}" -eq 0 ]]; then fetch_source_branch "" else fetch_ok=0 for git_remote_candidate in "${GIT_REMOTE_CANDIDATES[@]}"; do if fetch_source_branch "${git_remote_candidate}"; then GIT_REMOTE_URL="${git_remote_candidate}" fetch_ok=1 break fi echo "[jenkins-checkout-source] Git 远端拉取失败: ${git_remote_candidate}" >&2 done if [[ "${fetch_ok}" -ne 1 ]]; then echo "[jenkins-checkout-source] 所有 Git 远端均拉取失败。" >&2 exit 1 fi fi if [[ -n "${COMMIT_HASH}" && "$(git rev-parse --is-shallow-repository 2>/dev/null || echo false)" == "true" ]]; then git fetch --unshallow --no-tags origin "+refs/heads/${SOURCE_BRANCH}:refs/remotes/origin/${SOURCE_BRANCH}" || true fi git cat-file -e "refs/remotes/origin/${SOURCE_BRANCH}^{commit}" if [[ -n "${COMMIT_HASH}" ]]; then git cat-file -e "${COMMIT_HASH}^{commit}" RESOLVED_COMMIT="$(git rev-parse "${COMMIT_HASH}^{commit}")" if ! git merge-base --is-ancestor "${RESOLVED_COMMIT}" "refs/remotes/origin/${SOURCE_BRANCH}"; then echo "[jenkins-checkout-source] 指定 commit 不属于 origin/${SOURCE_BRANCH}: ${RESOLVED_COMMIT}" >&2 exit 1 fi else RESOLVED_COMMIT="$(git rev-parse "refs/remotes/origin/${SOURCE_BRANCH}^{commit}")" fi git checkout --detach "${RESOLVED_COMMIT}" git reset --hard HEAD git clean -fd printf "%s\n" "${RESOLVED_COMMIT}" >"${SOURCE_COMMIT_FILE}" echo "[jenkins-checkout-source] 使用源码: branch=${SOURCE_BRANCH} commit=${RESOLVED_COMMIT} remote=${GIT_REMOTE_URL:-origin}"