@@ -154,20 +154,60 @@ jobs:
154154 print(f"Rewrote {len(paths)} task GUIDs and names.")
155155 PYEOF
156156
157+ - name : Resolve next extension version
158+ id : version
159+ # Marketplace requires each publish of a (publisher, extension-id) to
160+ # use a version strictly greater than the currently published one, and
161+ # ADO only auto-updates to a higher version.
162+ #
163+ # Preferred (traceable) version is 0.<PR#>.<run_number>. But this e2e
164+ # extension is shared across all runs and already has older publishes
165+ # (e.g. 0.647.87), so a low PR/run can be <= what's live and get
166+ # rejected. Strategy:
167+ # • candidate = 0.<PR#>.<run_number>
168+ # • query the version currently live on Marketplace
169+ # • if candidate > live → publish candidate (keeps traceability)
170+ # • if candidate <= live → take live and bump its patch (+1)
171+ # When no Marketplace PAT is available we can't query, so we just emit
172+ # the candidate (the publish step is skipped in that case anyway).
173+ env :
174+ MARKETPLACE_PAT : ${{ secrets.ADO_E2E_MARKETPLACE_PAT }}
175+ PUBLISHER : " ${{ secrets.ADO_E2E_PUBLISHER_ORG || secrets.ADO_E2E_ORG }}-private"
176+ EXTENSION_ID : " ${{ secrets.ADO_E2E_EXTENSION_ID || 'jfrog-azure-devops-extension-e2etest' }}"
177+ PR_NUMBER : ${{ github.event.pull_request.number || 0 }}
178+ RUN_NUMBER : ${{ github.run_number }}
179+ run : |
180+ set -euo pipefail
181+ export CANDIDATE="0.${PR_NUMBER}.${RUN_NUMBER}"
182+ export LIVE="0.0.0"
183+ if [ -n "${MARKETPLACE_PAT:-}" ]; then
184+ TFX_OUT=$(npx --yes tfx-cli extension show --publisher "$PUBLISHER" --extension-id "$EXTENSION_ID" --token "$MARKETPLACE_PAT" 2>&1 || true)
185+ LIVE=$(echo "$TFX_OUT" | python3 -c "import sys,json; raw=sys.stdin.read(); s=raw.find('{'); d=json.loads(raw[s:]) if s>=0 else {}; v=d.get('versions',[]); print(v[0]['version'] if v else '0.0.0')" 2>/dev/null || echo '0.0.0')
186+ [ -z "$LIVE" ] && LIVE='0.0.0'
187+ export LIVE
188+ fi
189+ echo "Live version on Marketplace : $LIVE"
190+ echo "Candidate (0.PR.run) : $CANDIDATE"
191+ python3 - <<'PY' >> "$GITHUB_OUTPUT"
192+ import os
193+ def parse(v):
194+ parts = (str(v).split('.') + ['0', '0', '0'])[:3]
195+ return [int(p) if p.isdigit() else 0 for p in parts]
196+ cand = os.environ['CANDIDATE']
197+ live = os.environ['LIVE']
198+ c, l = parse(cand), parse(live)
199+ final = cand if c > l else f"{l[0]}.{l[1]}.{l[2] + 1}"
200+ print(f"vsix_version={final}")
201+ PY
202+ echo "Resolved version written to job output."
203+
157204 - name : Package .vsix
158205 id : build_vsix
159206 env :
160- # Version must be strictly increasing for a single (publisher,
161- # extension-id) — Marketplace rejects re-publishing an equal/lower
162- # version, and ADO only auto-updates to a higher one. Since this
163- # extension id is shared across every E2E run/PR, a PR-number-based
164- # version would go backwards when an older PR runs after a newer one.
165- # github.run_number is globally monotonic per workflow, and
166- # github.run_attempt increments on "Re-run", so
167- # 0.<run_number>.<run_attempt> is always increasing — no collisions
168- # on re-runs (the exact bug that got auto-publish removed before).
169- # The PR number is still surfaced in the artifact name + job summary.
170- VSIX_VERSION : " 0.${{ github.run_number }}.${{ github.run_attempt }}"
207+ # Version resolved above: preferred 0.<PR#>.<run_number>, or a
208+ # patch-bump of the live Marketplace version when that would
209+ # otherwise be <= what's already published.
210+ VSIX_VERSION : ${{ steps.version.outputs.vsix_version }}
171211 # Bake the real destination publisher into the .vsix at build time.
172212 # Marketplace rejects uploads if the manifest publisher and the
173213 # destination publisher don't match exactly, so we cannot use a
0 commit comments