@@ -118,32 +118,61 @@ jobs:
118118 if : steps.commit.outputs.pr_required != 'true'
119119 run : echo "No regenerated changes — nothing to create a PR for."
120120
121- # Sync main after merge
121+ # Sync main after merge (force fetch tags + main)
122122 - name : Sync main after merge
123123 if : steps.commit.outputs.pr_required == 'true'
124124 run : |
125125 set -euo pipefail
126+ echo "Waiting for GitHub to update merge state..."
127+ # give GitHub a moment
126128 sleep 10
127- git fetch origin main --tags
129+ # force fetch main and tags from remote to ensure runner sees latest
130+ git fetch origin main --force
131+ git fetch origin --tags --force
128132 git checkout main
129133 git reset --hard origin/main
134+ echo "Main branch and tags synced successfully."
130135
131- # Determine new tag (SemVer Patch)
136+ # Determine new tag (SemVer Patch) — robust: read remote tags, sort, and ensure uniqueness
132137 - name : Determine new tag version
133138 if : steps.commit.outputs.pr_required == 'true'
134139 id : tag
135140 run : |
136141 set -euo pipefail
137- LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0")
142+ # Make sure we have up-to-date tags
143+ git fetch origin --tags --force
144+
145+ # List remote tags that match semver vMAJOR.MINOR.PATCH
146+ # Use ls-remote to be sure we check remote state
147+ TAGS=$(git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sed 's/\^{}//g' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true)
148+
149+ if [ -z "${TAGS:-}" ]; then
150+ LAST_TAG="v1.0.0"
151+ else
152+ # pick highest semantic version (sort -V works on ubuntu)
153+ LAST_TAG=$(echo "$TAGS" | sort -V | tail -n1)
154+ fi
155+
156+ echo "Last tag detected: ${LAST_TAG}"
157+
158+ # Parse components safely
138159 IFS='.' read -r MAJOR MINOR PATCH <<<"${LAST_TAG#v}"
139160 MAJOR=${MAJOR:-1}
140161 MINOR=${MINOR:-0}
141162 PATCH=${PATCH:-0}
142163
164+ # increment patch
143165 PATCH=$((PATCH+1))
144166 NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
167+
168+ # ensure uniqueness in remote (race protection) - bump patch until unique
169+ while git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sed 's/\^{}//g' | grep -qx "${NEW_TAG}"; do
170+ PATCH=$((PATCH+1))
171+ NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
172+ done
173+
174+ echo "Determined new tag: ${NEW_TAG}"
145175 echo "new_tag=${NEW_TAG}" >> $GITHUB_OUTPUT
146- echo "Next tag determined: ${NEW_TAG}"
147176
148177 # Create and push tag
149178 - name : Create and push tag
@@ -154,16 +183,17 @@ jobs:
154183 run : |
155184 set -euo pipefail
156185 NEW_TAG="${{ steps.tag.outputs.new_tag }}"
157- git fetch --tags
158186
159- if git rev-parse "refs/tags/${NEW_TAG}" >/dev/null 2>&1; then
160- echo "Tag ${NEW_TAG} already exists. Skipping."
187+ # final safety check: if tag already exists remotely, skip
188+ if git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sed 's/\^{}//g' | grep -qx "${NEW_TAG}"; then
189+ echo "Tag ${NEW_TAG} already exists on remote. Skipping."
161190 echo "tag_created=false" >> $GITHUB_OUTPUT
162191 exit 0
163192 fi
164193
165194 git tag -a "${NEW_TAG}" -m "Release ${NEW_TAG} (automated)"
166- git push "https://x-access-token:${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "${NEW_TAG}"
195+ git push "https://x-access-token:${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "refs/tags/${NEW_TAG}"
196+
167197 echo "tag_created=true" >> $GITHUB_OUTPUT
168198 echo "Created tag ${NEW_TAG}"
169199
0 commit comments