chore: enforce standard branch release workflow
This commit is contained in:
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BASE_REF="${BASE_REF:-}"
|
||||
SKIP_FETCH=0
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
bash scripts/check-branch-baseline.sh [--skip-fetch]
|
||||
|
||||
Checks that the current branch is not behind origin/main.
|
||||
|
||||
Environment:
|
||||
BASE_REF Base ref to compare against. Defaults to origin/main when available.
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--skip-fetch) SKIP_FETCH=1 ;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
git -C "${ROOT}" rev-parse --is-inside-work-tree >/dev/null
|
||||
|
||||
if [[ "${SKIP_FETCH}" -ne 1 ]] && git -C "${ROOT}" remote get-url origin >/dev/null 2>&1; then
|
||||
git -C "${ROOT}" fetch origin --prune
|
||||
fi
|
||||
|
||||
if [[ -z "${BASE_REF}" ]]; then
|
||||
for candidate in origin/main origin/master main master; do
|
||||
if git -C "${ROOT}" rev-parse --verify --quiet "${candidate}" >/dev/null; then
|
||||
BASE_REF="${candidate}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
branch="$(git -C "${ROOT}" branch --show-current)"
|
||||
if [[ -z "${branch}" ]]; then
|
||||
echo "Baseline check failed: detached HEAD is not allowed for development or release." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git -C "${ROOT}" rev-parse --verify --quiet "${BASE_REF}" >/dev/null; then
|
||||
echo "Baseline check failed: base ref not found: ${BASE_REF}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -r ahead behind < <(git -C "${ROOT}" rev-list --left-right --count "HEAD...${BASE_REF}")
|
||||
|
||||
if [[ "${behind}" -ne 0 ]]; then
|
||||
echo "Baseline check failed: ${branch} is behind ${BASE_REF} by ${behind} commit(s)." >&2
|
||||
echo "Run: git fetch origin --prune && git rebase ${BASE_REF}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Baseline check passed: ${branch} is current with ${BASE_REF} (ahead ${ahead})."
|
||||
Executable
+79
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BASE_REF="${BASE_REF:-}"
|
||||
SKIP_FETCH=0
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
bash scripts/check-release-ready.sh [--skip-fetch]
|
||||
|
||||
Blocks releases unless the repository is on a named branch, the branch is not
|
||||
behind origin/main, and the worktree is clean.
|
||||
|
||||
Environment:
|
||||
BASE_REF Base ref to compare against. Defaults to origin/main when available.
|
||||
ALLOW_MAIN_RELEASE=1 Allow publishing directly from main/master.
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--skip-fetch) SKIP_FETCH=1 ;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
git -C "${ROOT}" rev-parse --is-inside-work-tree >/dev/null
|
||||
|
||||
branch="$(git -C "${ROOT}" branch --show-current)"
|
||||
if [[ -z "${branch}" ]]; then
|
||||
echo "Release check failed: detached HEAD is not a release source." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "${branch}" in
|
||||
main|master)
|
||||
if [[ "${ALLOW_MAIN_RELEASE:-0}" != "1" ]]; then
|
||||
echo "Release check failed: publish from a dedicated release/feature branch, not ${branch}." >&2
|
||||
echo "Set ALLOW_MAIN_RELEASE=1 only for an explicitly approved mainline release." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n "$(git -C "${ROOT}" status --porcelain=v1 --untracked-files=all)" ]]; then
|
||||
echo "Release check failed: worktree has uncommitted or untracked changes." >&2
|
||||
git -C "${ROOT}" status --short --untracked-files=all >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${SKIP_FETCH}" -eq 1 ]]; then
|
||||
bash "${ROOT}/scripts/check-branch-baseline.sh" --skip-fetch
|
||||
else
|
||||
bash "${ROOT}/scripts/check-branch-baseline.sh"
|
||||
fi
|
||||
|
||||
effective_base="${BASE_REF}"
|
||||
if [[ -z "${effective_base}" ]]; then
|
||||
for candidate in origin/main origin/master main master; do
|
||||
if git -C "${ROOT}" rev-parse --verify --quiet "${candidate}" >/dev/null; then
|
||||
effective_base="${candidate}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
head_sha="$(git -C "${ROOT}" rev-parse --short HEAD)"
|
||||
echo "Release check passed: ${branch} @ ${head_sha} is clean and current with ${effective_base}."
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BASE_REF="${BASE_REF:-}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
bash scripts/new-branch.sh <branch-name>
|
||||
|
||||
Creates a new development branch from the latest origin/main.
|
||||
|
||||
Environment:
|
||||
BASE_REF Base ref to create from. Defaults to origin/main when available.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" || $# -ne 1 ]]; then
|
||||
usage
|
||||
[[ $# -eq 1 ]] && exit 0 || exit 1
|
||||
fi
|
||||
|
||||
branch="$1"
|
||||
|
||||
if [[ -n "$(git -C "${ROOT}" status --porcelain=v1 --untracked-files=all)" ]]; then
|
||||
echo "New branch check failed: current worktree is not clean." >&2
|
||||
git -C "${ROOT}" status --short --untracked-files=all >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git -C "${ROOT}" remote get-url origin >/dev/null 2>&1; then
|
||||
git -C "${ROOT}" fetch origin --prune
|
||||
fi
|
||||
|
||||
if [[ -z "${BASE_REF}" ]]; then
|
||||
for candidate in origin/main origin/master main master; do
|
||||
if git -C "${ROOT}" rev-parse --verify --quiet "${candidate}" >/dev/null; then
|
||||
BASE_REF="${candidate}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
git -C "${ROOT}" rev-parse --verify --quiet "${BASE_REF}" >/dev/null || {
|
||||
echo "New branch check failed: base ref not found: ${BASE_REF}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
git -C "${ROOT}" switch -c "${branch}" "${BASE_REF}"
|
||||
echo "Created ${branch} from ${BASE_REF}."
|
||||
@@ -84,6 +84,13 @@ need_cmd scp
|
||||
need_cmd tar
|
||||
need_cmd shasum
|
||||
|
||||
if [[ -x "${ROOT}/scripts/check-release-ready.sh" ]]; then
|
||||
bash "${ROOT}/scripts/check-release-ready.sh"
|
||||
else
|
||||
echo "缺少发布前闸门: ${ROOT}/scripts/check-release-ready.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_release_scope() {
|
||||
local bypass="${ALLOW_PORTAL_RELEASE_SCOPE_BYPASS:-0}"
|
||||
if [[ "${bypass}" == "1" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user