@@ -22,6 +22,9 @@ inputs:
2222 coverage :
2323 description : " Coverage percentage (e.g. 83 or 83%)"
2424 required : true
25+ branch :
26+ description : " Optional source branch name override (recommended for tag-triggered workflows)"
27+ required : false
2528 report :
2629 description : " Optional path to an HTML coverage report file to publish as report.html"
2730 required : false
3942 - name : Detect current branch (handles tags; fetches tags; robust)
4043 id : branch
4144 shell : bash
45+ env :
46+ INPUT_BRANCH : ${{ inputs.branch }}
4247 run : |
4348 set -euo pipefail
4449
6166 # Fetch all remote heads so we can query them locally
6267 git fetch origin +refs/heads/*:refs/remotes/origin/* --prune
6368
69+ # Explicit override: useful for tag workflows where multiple branches may contain the tag.
70+ BRANCH="${INPUT_BRANCH:-}"
71+ BRANCH="$(echo "$BRANCH" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
72+ if [[ -n "$BRANCH" ]]; then
73+ if [[ "$BRANCH" == "HEAD" || "$BRANCH" =~ ^\(.+\)$ ]]; then
74+ echo "Invalid explicit branch input: '$BRANCH'" >&2
75+ exit 1
76+ fi
77+ if ! git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then
78+ echo "Explicit branch '$BRANCH' was not found on origin." >&2
79+ exit 1
80+ fi
81+ echo "Using explicit branch input: $BRANCH"
82+ echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
83+ exit 0
84+ fi
85+
6486 # --- Fast paths: PR source branch or branch ref ---
6587 if [[ -n "${GITHUB_HEAD_REF:-}" ]]; then
6688 BRANCH="${GITHUB_HEAD_REF}"
@@ -74,39 +96,64 @@ runs:
7496 if [[ -z "$BRANCH" ]] && { [[ "${GITHUB_REF_TYPE:-}" == "tag" ]] || [[ "${GITHUB_REF:-}" == refs/tags/* ]]; }; then
7597 TAG="${GITHUB_REF_NAME:-${GITHUB_REF#refs/tags/}}"
7698 TAG_REF="tags/$TAG"
99+ TAG_SHA="$(git rev-list -n1 "$TAG_REF")"
77100 echo "Ref is a tag (${TAG}); resolving containing branch..."
78101
79- # 1) Prefer remote branches that contain the tag commit
102+ # 1) Gather remote branches that contain the tag commit
80103 CANDIDATES=()
81104 while IFS= read -r r; do
82105 [[ -z "$r" || "$r" == origin/HEAD ]] && continue
83106 CANDIDATES+=("${r#origin/}")
84107 done < <(git branch -r --format "%(refname:short)" --contains "$TAG_REF" 2>/dev/null || true)
85108
86- # 2) If none (common in shallow graphs), pick branches whose TIP == tag commit
87- if [[ ${#CANDIDATES[@]} -eq 0 ]]; then
88- TAG_SHA="$(git rev-list -n1 "$TAG_REF")"
89- while IFS= read -r rb; do
90- [[ -z "$rb" ]] && continue
91- [[ "$rb" == origin/HEAD ]] && continue
92- b="${rb#origin/}"
93- BR_SHA="$ (git rev-parse "$rb" 2>/dev/null || true)"
94- [[ -n "$BR_SHA" && "$BR_SHA" == "$TAG_SHA" ]] && CANDIDATES+=("$b")
95- done < <(git for-each-ref --format='%(refname:short)' refs/remotes/origin/ )
109+ # 2) Prefer branches whose TIP exactly matches the tagged commit.
110+ TIP_MATCHES=()
111+ while IFS= read -r rb; do
112+ [[ -z "$rb" || "$rb" == origin/HEAD ]] && continue
113+ b="${rb#origin/}"
114+ BR_SHA="$(git rev-parse "$rb" 2>/dev/null || true)"
115+ [[ -n "$BR_SHA" && "$BR_SHA" == "$TAG_SHA" ]] && TIP_MATCHES+=("$b")
116+ done < < (git for-each-ref --format='%(refname:short)' refs/remotes/origin/)
117+ if [[ ${#TIP_MATCHES[@]} -gt 0 ]]; then
118+ CANDIDATES=("${TIP_MATCHES[@]}" )
96119 fi
97120
98- # 3) Choose best candidate: origin/HEAD > main/master > first
121+ # 3) Choose nearest containing branch by smallest ahead distance from tag commit.
122+ # If still ambiguous, fail instead of silently picking the wrong branch.
99123 DEF="$(resolve_default_branch)"
100- if [[ -n "$DEF" ]]; then
101- for b in "${CANDIDATES[@]}"; do [[ "$b" == "$DEF" ]] && BRANCH="$b" && break; done
102- fi
103- if [[ -z "$BRANCH" ]]; then
104- for pref in main master; do
105- for b in "${CANDIDATES[@]}"; do [[ "$b" == "$pref" ]] && BRANCH="$b" && break 2; done
106- done
107- fi
108- if [[ -z "$BRANCH" && ${#CANDIDATES[@]} -gt 0 ]]; then
124+ if [[ ${#CANDIDATES[@]} -eq 1 ]]; then
109125 BRANCH="${CANDIDATES[0]}"
126+ elif [[ ${#CANDIDATES[@]} -gt 1 ]]; then
127+ BEST_BRANCH=""
128+ BEST_DIST=""
129+ TIED=0
130+ for b in "${CANDIDATES[@]}"; do
131+ dist="$(git rev-list --count "${TAG_REF}..origin/${b}" 2>/dev/null || echo 999999)"
132+ [[ "$dist" =~ ^[0-9]+$ ]] || dist=999999
133+ if [[ -z "$BEST_DIST" || "$dist" -lt "$BEST_DIST" ]]; then
134+ BEST_DIST="$dist"
135+ BEST_BRANCH="$b"
136+ TIED=0
137+ elif [[ "$dist" -eq "$BEST_DIST" ]]; then
138+ if [[ -n "$DEF" && "$b" == "$DEF" ]]; then
139+ BEST_BRANCH="$b"
140+ TIED=0
141+ elif [[ -n "$DEF" && "$BEST_BRANCH" == "$DEF" ]]; then
142+ :
143+ else
144+ TIED=1
145+ fi
146+ fi
147+ done
148+
149+ if [[ -n "$BEST_BRANCH" && "$TIED" -eq 0 ]]; then
150+ BRANCH="$BEST_BRANCH"
151+ else
152+ echo "Ambiguous tag-to-branch mapping for tag '${TAG}'." >&2
153+ echo "Candidates: ${CANDIDATES[*]}" >&2
154+ echo "Set input 'branch' to the intended source branch." >&2
155+ exit 1
156+ fi
110157 fi
111158 fi
112159
0 commit comments