From 3badb955f5e3e676ec1eaa86417d716cb4783b75 Mon Sep 17 00:00:00 2001 From: Vincent Giersch Date: Fri, 11 Sep 2026 14:29:50 +0200 Subject: [PATCH] fix(release): tag with the v prefix, and publish a GitHub release Two things the release path got wrong, both visible on the repository page. The tag carried no prefix. Every tag in this repository, and every tag in api-reference, is v-prefixed, and the workflows introduced with the new pipeline created a bare one from the VERSION file. The tag list now mixes the two styles. tag-on-merge creates vX.Y.Z, release.yml triggers on it, and the assertion that the tag matches the packaged version compares against the tag with the v stripped, because the version inside the package never carries it. The four tags already published (2.0.0 and 2.0.1 here, 1.0.0 in the ruby and javascript clients) are left as they are: the registries record those versions and moving a published tag gains nothing. Nothing created a GitHub release, only a tag, so the Releases page still presented a version from 2018 as the latest one, which is what anyone browsing the repository sees first. release.yml now creates it, taking the notes from the CHANGELOG section for the version so the release says what changed. That needs contents: write, which the job did not have. A re-tag is a no-op now, not a failed release. npm error You cannot publish over the previously published versions: 1.0.0. Nothing was damaged: the published package is the same artifact and is still installable. But a red release on a version that is correctly out is the kind of failure people learn to ignore, and re-running a release, or changing the tag scheme as this just did, are both ordinary things to do. The publish step is skipped when the version is already in the registry, and the GitHub release step reports and moves on when the release exists rather than erroring on the create. --- .github/workflows/release.yml | 48 +++++++++++++++++++++++++++--- .github/workflows/tag-on-merge.yml | 4 ++- CHANGELOG.md | 16 ++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec4e18d..2b150d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ name: Release on: push: - tags: ['[0-9]+.[0-9]+.[0-9]+'] + tags: ['v[0-9]+.[0-9]+.[0-9]+'] permissions: contents: write # create the GitHub release for the tag @@ -24,7 +24,9 @@ jobs: - name: The tag must match the packaged version run: | - TAG="${GITHUB_REF_NAME}" + # Every tag in this repository, and in api-reference, carries the v. The version + # inside the package never does, so the tag is compared with it stripped. + TAG="${GITHUB_REF_NAME#v}" PKG="$(cat VERSION)" [ "$TAG" = "$PKG" ] || { echo "tag $TAG != VERSION $PKG"; exit 1; } @@ -35,7 +37,9 @@ jobs: # lets a version be replaced, so this has to fail here rather than after the upload. - name: The built artifact must carry the tagged version run: | - TAG="${GITHUB_REF_NAME}" + # Every tag in this repository, and in api-reference, carries the v. The version + # inside the package never does, so the tag is compared with it stripped. + TAG="${GITHUB_REF_NAME#v}" test -f "dist/flat_api-${TAG}-py3-none-any.whl" || { echo "no wheel for ${TAG}; dist/ holds:"; ls dist/; exit 1; } @@ -44,7 +48,19 @@ jobs: } # No long-lived token exists: PyPI trusts this repository and workflow by OIDC. + - name: Skip the publish if this version is already on PyPI + id: published + run: | + VERSION="${GITHUB_REF_NAME#v}" + if curl -fsS "https://pypi.org/pypi/flat-api/$VERSION/json" >/dev/null 2>&1; then + echo "flat-api $VERSION is already on PyPI; nothing to publish." + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - name: Publish to PyPI (trusted publishing) + if: steps.published.outputs.skip != 'true' uses: pypa/gh-action-pypi-publish@release/v1 with: attestations: true @@ -55,7 +71,9 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - TAG="${GITHUB_REF_NAME}" + # Every tag in this repository, and in api-reference, carries the v. The version + # inside the package never does, so the tag is compared with it stripped. + TAG="${GITHUB_REF_NAME#v}" NOTES="$(awk -v tag="$TAG" ' $0 ~ "^## \\[?" tag {found=1; next} found && /^## / {exit} @@ -65,3 +83,25 @@ jobs: printf '%s\n\n---\n\nInstall: `pip install flat-api==%s`\n' "$NOTES" "$TAG" \ > /tmp/notes.md gh release create "$TAG" --title "$TAG" --notes-file /tmp/notes.md --verify-tag + + # The tag alone left the repository's Releases page showing a version from years ago as + # "Latest", which is what anyone browsing the repository sees first. The notes come from the + # CHANGELOG section for this version, so the release says what changed rather than nothing. + - name: Publish the GitHub release + env: + GH_TOKEN: ${{ github.token }} + run: | + VERSION="${GITHUB_REF_NAME#v}" + NOTES="$(awk -v v="$VERSION" ' + $0 ~ "^## \\[?" v "\\]?" { found = 1; next } + found && /^## / { exit } + found { print } + ' CHANGELOG.md)" + [ -n "$NOTES" ] || NOTES="See CHANGELOG.md for $VERSION." + # Creating one that exists is an error, and a re-run of a release that already happened + # should be a no-op rather than a red build. + if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then + echo "Release $GITHUB_REF_NAME already exists; nothing to do." + else + gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes "$NOTES" + fi diff --git a/.github/workflows/tag-on-merge.yml b/.github/workflows/tag-on-merge.yml index 477d6d6..f1bc04e 100644 --- a/.github/workflows/tag-on-merge.yml +++ b/.github/workflows/tag-on-merge.yml @@ -36,7 +36,9 @@ jobs: token: ${{ secrets.SDK_RELEASE_TOKEN }} - name: Tag the version if it is new run: | - VERSION="$(cat VERSION)" + # v-prefixed, matching every tag this repository and api-reference already carry. + # The version inside the package stays bare; only the git tag is prefixed. + VERSION="v$(cat VERSION)" if git rev-parse "$VERSION" >/dev/null 2>&1; then echo "Tag $VERSION already exists, nothing to do." exit 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 700abe3..42000a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,22 @@ * **docs:** close the asynchronous usage code fence in the README. Two escapes had been written as the literal characters `\n` rather than newlines, so the fence never opened or closed and every section after it rendered inside the code block on PyPI. +## [2.0.0](https://github.com/FlatIO/api-client-python/compare/v1.1.3...2.0.0) (2026-09-11) + +The first release of the 2.x line. Regenerated against API specification 2.26.0, covering all 123 +public operations. See [MIGRATION.md](MIGRATION.md) for the upgrade from 1.x. + +### Features + +* Typed errors, retries with backoff, `Link` header pagination and OAuth2 token refresh. +* Both `FlatClient` and `AsyncFlatClient` in one package. The generator emits sync or async and + never both, so the package is generated twice and merged. + +### Breaking Changes + +* Requires Python 3.9 or later. +* Models and operations are regenerated, so names follow the current specification. + ## [1.1.3](https://github.com/FlatIO/api-client-python/compare/v1.1.2...v1.1.3) (2024-03-08)