diff --git a/.github/actions/is-newest-version/action.yml b/.github/actions/is-newest-version/action.yml new file mode 100644 index 00000000000..89c8d2e775f --- /dev/null +++ b/.github/actions/is-newest-version/action.yml @@ -0,0 +1,44 @@ +name: Is newest version +description: > + Decide whether the version being released is the newest of the repository's + v* tags, so release workflows can keep floating pointers (the GitHub + "latest" marker, :latest image tags, live docs and sandboxes) on the newest + version when shipping a backport from an old release line. Requires a + checkout with tags fetched; the new release's own tag must not exist yet. + +inputs: + version: + description: The version being released, without the leading v. + required: true + +outputs: + is_newest: + description: '"true" when the version is >= every existing v* tag, else "false".' + value: ${{ steps.compare.outputs.is_newest }} + +runs: + using: composite + steps: + - id: compare + shell: bash + env: + VERSION: ${{ inputs.version }} + run: | + # Strict X.Y.Z filter: a stray non-numeric tag (vnext) or a + # pre-release tag (v1.2.3-rc1) would otherwise outrank real versions + # under sort -V and silently flip a normal release to a backport. + highest=$(git tag --list 'v[0-9]*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//' | sort -V | tail -1 || true) + # Fail closed: an empty tag list on a release repo means the checkout + # did not fetch tags. Guessing "newest" here would move every + # floating pointer onto whatever is being released. + if [ -z "$highest" ]; then + echo "::error::no vX.Y.Z tags visible; was the checkout made with fetch-tags?" + exit 1 + fi + if [ "$(printf '%s\n%s\n' "$highest" "$VERSION" | sort -V | tail -1)" = "$VERSION" ]; then + echo "is_newest=true" >> "$GITHUB_OUTPUT" + echo "v$VERSION is the newest version (highest existing tag: v$highest)" + else + echo "is_newest=false" >> "$GITHUB_OUTPUT" + echo "v$VERSION is a backport (highest existing tag: v$highest); floating pointers stay put" + fi diff --git a/.github/workflows/ci-post-release.yml b/.github/workflows/ci-post-release.yml index e0c7d9e3025..0e723d43f2a 100644 --- a/.github/workflows/ci-post-release.yml +++ b/.github/workflows/ci-post-release.yml @@ -189,36 +189,59 @@ jobs: - name: Determine current version based on pipeline-manager run: | echo "CURRENT_VERSION=$(cargo metadata --no-deps | jq -r '.packages[]|select(.name == "pipeline-manager")|.version')" >> $GITHUB_ENV + # A backport release (published from an old release branch) must not + # bump main's version: main is already versions ahead of it. Bump only + # when the published release is at least main's current version. A + # manual workflow_dispatch carries no release tag and always bumps. + - name: Check that the published release is not a backport + id: bump-check + env: + RELEASED_TAG: ${{ github.event.release.tag_name }} + run: | + released="${RELEASED_TAG#v}" + if [ -n "$released" ] && [ "$(printf '%s\n%s\n' "$released" "$CURRENT_VERSION" | sort -V | head -1)" = "$released" ] && [ "$released" != "$CURRENT_VERSION" ]; then + echo "bump=false" >> "$GITHUB_OUTPUT" + echo "Release v$released is older than main's v$CURRENT_VERSION: skipping the version bump" + else + echo "bump=true" >> "$GITHUB_OUTPUT" + fi - name: Bump cargo versions + if: ${{ steps.bump-check.outputs.bump == 'true' }} run: | cargo set-version --bump ${{ vars.RELEASE_NEXT_VERSION }} cargo run --release --locked --bin pipeline-manager -- --dump-openapi - name: Determine next version based on pipeline-manager + if: ${{ steps.bump-check.outputs.bump == 'true' }} run: | echo "NEXT_VERSION=$(cargo metadata --no-deps | jq -r '.packages[]|select(.name == "pipeline-manager")|.version')" >> $GITHUB_ENV - name: Adjust python version + if: ${{ steps.bump-check.outputs.bump == 'true' }} working-directory: ./python run: | sed -i "s/version = \"${{ env.CURRENT_VERSION }}\"/version = \"${{ env.NEXT_VERSION }}\"/g" pyproject.toml uv sync - name: Adjust dbt-feldera version + if: ${{ steps.bump-check.outputs.bump == 'true' }} working-directory: ./python/dbt-feldera run: | sed -i "s/version = \"${{ env.CURRENT_VERSION }}\"/version = \"${{ env.NEXT_VERSION }}\"/g" pyproject.toml sed -i "s/version: '${{ env.CURRENT_VERSION }}'/version: '${{ env.NEXT_VERSION }}'/g" dbt/include/feldera/dbt_project.yml - name: Adjust felderize version + if: ${{ steps.bump-check.outputs.bump == 'true' }} working-directory: ./python/felderize run: | sed -i "s/version = \"${{ env.CURRENT_VERSION }}\"/version = \"${{ env.NEXT_VERSION }}\"/g" pyproject.toml - name: Adjust sql compiler version + if: ${{ steps.bump-check.outputs.bump == 'true' }} working-directory: ./sql-to-dbsp-compiler/SQL-compiler run: | sed -i "s|${{ env.CURRENT_VERSION }}|${{ env.NEXT_VERSION }}|g" pom.xml - name: List changes + if: ${{ steps.bump-check.outputs.bump == 'true' }} run: | git diff - uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # a94899bca583c204427a224a7af87c02f9b325d5 - if: ${{ vars.RELEASE_DRY_RUN == 'false' }} + if: ${{ vars.RELEASE_DRY_RUN == 'false' && steps.bump-check.outputs.bump == 'true' }} with: message: "ci: Prepare for v${{ env.NEXT_VERSION }}" push: origin main diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index f503eff2af2..62bc06bdcc4 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -64,6 +64,15 @@ jobs: ref: ${{ env.SHA_TO_RELEASE }} persist-credentials: false + # A backport release on an old version line must not move any floating + # pointer: the GitHub "latest" marker, the :latest docker tag, or the + # live docs site all have to keep tracking the newest version. + - name: Determine whether this version is the newest + id: newest + uses: ./.github/actions/is-newest-version + with: + version: ${{ env.CURRENT_VERSION }} + - name: Download artifact id: download-artifact uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 @@ -100,13 +109,13 @@ jobs: repositories: ${{ github.event.repository.name }} - name: Release on GitHub - uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # 72f2c25fcb47643c292f7107632f7a47c1df5cd8 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 with: target_commitish: ${{ env.SHA_TO_RELEASE }} tag_name: v${{ env.CURRENT_VERSION }} draft: ${{ vars.RELEASE_DRY_RUN }} generate_release_notes: true - make_latest: true + make_latest: ${{ steps.newest.outputs.is_newest }} files: | pipeline-manager-aarch64-unknown-linux-gnu.zip pipeline-manager-x86_64-unknown-linux-gnu.zip @@ -139,7 +148,9 @@ jobs: run: unzip feldera-docs.zip -d docs - name: Deploy docs.feldera.com - if: ${{ vars.RELEASE_DRY_RUN == 'false' }} + # is_newest: publishing a backport's docs would replace the live site + # with an old version's documentation. + if: ${{ vars.RELEASE_DRY_RUN == 'false' && steps.newest.outputs.is_newest == 'true' }} uses: JamesIves/github-pages-deploy-action@4ef313c6a410f0883308623d45510e4a11625465 # v4.7.5 with: folder: docs @@ -163,8 +174,14 @@ jobs: with: version: latest - - name: Tag docker image with version and latest + - name: Tag docker image with version if: ${{ vars.RELEASE_DRY_RUN == 'false' }} run: | docker buildx imagetools create -t ${{ vars.FELDERA_IMAGE_NAME }}:${{ env.CURRENT_VERSION }} ${{ vars.FELDERA_IMAGE_NAME }}:sha-${{ env.SHA_TO_RELEASE }} + + - name: Tag docker image as latest + # is_newest: moving :latest to a backport would downgrade every user + # who pulls the floating tag. + if: ${{ vars.RELEASE_DRY_RUN == 'false' && steps.newest.outputs.is_newest == 'true' }} + run: | docker buildx imagetools create -t ${{ vars.FELDERA_IMAGE_NAME }}:latest ${{ vars.FELDERA_IMAGE_NAME }}:sha-${{ env.SHA_TO_RELEASE }}