#!/usr/bin/env sh # deploy-route.sh — 判定一個 domain 存取庫的改動是否已進預設分支,決定走部署路線或工作樹路線。 # # 用法: deploy-route.sh [branch] # branch 不給就用目前分支。 # # 為什麼要有這支: marketplace 與 version-guard.sh 都讀存取庫的**預設分支**, # 停在 develop 的改動 jsc-cli:deploy 看不到,部署路線的完成條件永遠達不到。 # skill-new、skill-update、skill-delete、skillset-update 四支各抄一段同樣的判定散文, # 四份會各自漂移,所以下放成同一支腳本。 # # 判定: # 1. git fetch --prune origin,讓比對基準是遠端而不是本機殘影。 # 2. 預設分支依序取 origin/HEAD 的指向、遠端有沒有 master、遠端有沒有 main。 # 3. 待判分支的 HEAD 是不是 origin/{預設分支} 的祖先——是就代表已經合進去。 # # 輸出(stdout,一行一組 {鍵}{值}): # routedeploy|worktree 要走哪條路線 # default-branch{name} 比對用的預設分支 # branch{name} 被判定的分支 # head{sha} 被判定分支的 commit # pending{name} 只有 worktree 路線才有:還沒併進預設分支的分支名 # 說明與失敗原因走 stderr。 # # 結束碼: 0=deploy 路線,改動已在預設分支上,可以叫 jsc-cli:deploy # 3=worktree 路線,改動還沒進預設分支,要改對工作樹驗證並在回報裡點名待合的 PR # 2=用法錯誤(一或兩個參數) # 1=判不出來:路徑不是 git 存取庫、沒有 origin、fetch 失敗,或取不到預設分支。 # **1 不等於 worktree**:判不出來就停下問人,別自己挑一條路線走。 set -u usage() { echo 'usage: deploy-route.sh [branch]' >&2 exit 2 } [ "$#" -ge 1 ] && [ "$#" -le 2 ] || usage DOMAIN=${1%/} [ -n "$DOMAIN" ] || usage BRANCH=${2:-} [ -d "$DOMAIN/.git" ] || git -C "$DOMAIN" rev-parse --git-dir >/dev/null 2>&1 || { echo "不是 git 存取庫:$DOMAIN" >&2; exit 1; } git -C "$DOMAIN" remote get-url origin >/dev/null 2>&1 || { echo "存取庫沒有 origin 遠端,無從比對預設分支:$DOMAIN" >&2; exit 1; } git -C "$DOMAIN" fetch --prune --quiet origin >/dev/null 2>&1 || { echo "git fetch origin 失敗,比對基準會是本機殘影,先修連線再重跑:$DOMAIN" >&2; exit 1; } if [ -z "$BRANCH" ]; then BRANCH=$(git -C "$DOMAIN" rev-parse --abbrev-ref HEAD 2>/dev/null) || BRANCH='' fi [ -n "$BRANCH" ] && [ "$BRANCH" != HEAD ] || { echo "取不到目前分支名(可能在 detached HEAD),請用第二個參數指定分支:$DOMAIN" >&2; exit 1; } # 預設分支:先問 origin/HEAD,再退回遠端實際存在的 master、main。 DEFAULT=$(git -C "$DOMAIN" symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null) || DEFAULT='' DEFAULT=${DEFAULT#origin/} if [ -z "$DEFAULT" ]; then for cand in master main; do if git -C "$DOMAIN" rev-parse --verify --quiet "refs/remotes/origin/$cand" >/dev/null 2>&1; then DEFAULT=$cand break fi done fi [ -n "$DEFAULT" ] || { echo "取不到預設分支(origin/HEAD、origin/master、origin/main 都沒有):$DOMAIN" >&2; exit 1; } git -C "$DOMAIN" rev-parse --verify --quiet "refs/remotes/origin/$DEFAULT" >/dev/null 2>&1 || { echo "遠端沒有 origin/$DEFAULT:$DOMAIN" >&2; exit 1; } HEADSHA=$(git -C "$DOMAIN" rev-parse --verify --quiet "$BRANCH" 2>/dev/null) || HEADSHA='' [ -n "$HEADSHA" ] || { echo "取不到分支的 commit:$BRANCH" >&2; exit 1; } TAB=$(printf '\t') if git -C "$DOMAIN" merge-base --is-ancestor "$HEADSHA" "origin/$DEFAULT" 2>/dev/null; then ROUTE=deploy else ROUTE=worktree fi printf 'route%s%s\n' "$TAB" "$ROUTE" printf 'default-branch%s%s\n' "$TAB" "$DEFAULT" printf 'branch%s%s\n' "$TAB" "$BRANCH" printf 'head%s%s\n' "$TAB" "$HEADSHA" if [ "$ROUTE" = deploy ]; then echo "改動已在 origin/$DEFAULT 上,走部署路線:$DOMAIN" >&2 exit 0 fi printf 'pending%s%s\n' "$TAB" "$BRANCH" echo "改動還沒併進 origin/$DEFAULT,走工作樹路線;回報時要點名待合的 PR:$DOMAIN" >&2 exit 3