From 30ba9f1829d3c6fd610709ee266fdfa4598376ac Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Thu, 9 Oct 2025 05:42:06 -0500 Subject: [PATCH] feat(ci): Refactor release promotion logic (#3418) --- .../workflows/create-or-promote-release.yml | 75 +++++++++++++------ .github/workflows/promote.yml | 26 ++++--- 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/.github/workflows/create-or-promote-release.yml b/.github/workflows/create-or-promote-release.yml index 50da9d628..500eba742 100644 --- a/.github/workflows/create-or-promote-release.yml +++ b/.github/workflows/create-or-promote-release.yml @@ -28,64 +28,95 @@ permissions: attestations: write jobs: - create-tag: + determine-tags: runs-on: ubuntu-latest outputs: - new_tag: ${{ steps.calculate_new_tag.outputs.new_tag }} + tag_to_process: ${{ steps.calculate_tags.outputs.tag_to_process }} + release_name: ${{ steps.calculate_tags.outputs.release_name }} + final_tag: ${{ steps.calculate_tags.outputs.final_tag }} steps: - name: Checkout code uses: actions/checkout@v5 with: fetch-depth: 0 - - name: Calculate new release tag - id: calculate_new_tag + - name: Calculate tags + id: calculate_tags run: | BASE_VERSION="${{ inputs.base_version }}" CHANNEL="${{ inputs.channel }}" - if [[ "$CHANNEL" == "production" ]]; then - # Production tags are simple, without a channel or increment - NEW_TAG="v${BASE_VERSION}" - else - # Pre-release channels get an incrementing number - LATEST_TAG=$(git tag --list "v${BASE_VERSION}-${CHANNEL}.*" --sort=-v:refname | head -n 1) + if [[ "$CHANNEL" == "internal" ]]; then + # This is a new build, create a new internal tag + LATEST_TAG=$(git tag --list "v${BASE_VERSION}-internal.*" --sort=-v:refname | head -n 1) if [ -z "$LATEST_TAG" ]; then INCREMENT=1 else - INCREMENT=$(echo "$LATEST_TAG" | sed -n "s/.*-${CHANNEL}\.\([0-9]*\)/\1/p" | awk '{print $1+1}') + INCREMENT=$(echo "$LATEST_TAG" | sed -n "s/.*-internal\.\([0-9]*\)/\1/p" | awk '{print $1+1}') fi - NEW_TAG="v${BASE_VERSION}-${CHANNEL}.${INCREMENT}" - fi + NEW_TAG="v${BASE_VERSION}-internal.${INCREMENT}" + echo "Calculated new tag: $NEW_TAG" + echo "tag_to_process=$NEW_TAG" >> $GITHUB_OUTPUT + echo "release_name=$NEW_TAG" >> $GITHUB_OUTPUT + echo "final_tag=$NEW_TAG" >> $GITHUB_OUTPUT + else + # This is a promotion, find the latest internal tag to promote + LATEST_INTERNAL_TAG=$(git tag --list "v${BASE_VERSION}-internal.*" --sort=-v:refname | head -n 1) - echo "Calculated new tag: $NEW_TAG" - echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT + if [ -z "$LATEST_INTERNAL_TAG" ]; then + echo "::error::No internal release found for base version ${BASE_VERSION} to promote." + exit 1 + fi + + echo "Found latest internal tag to promote: $LATEST_INTERNAL_TAG" + INCREMENT=$(echo "$LATEST_INTERNAL_TAG" | sed -n "s/.*-internal\.\([0-9]*\)/\1/p") + + if [[ "$CHANNEL" == "production" ]]; then + NEW_TAG="v${BASE_VERSION}" + else + NEW_TAG="v${BASE_VERSION}-${CHANNEL}.${INCREMENT}" + fi + + echo "New release name will be: $NEW_TAG" + echo "Final tag will be: $NEW_TAG" + echo "tag_to_process=$LATEST_INTERNAL_TAG" >> $GITHUB_OUTPUT + echo "release_name=$NEW_TAG" >> $GITHUB_OUTPUT + echo "final_tag=$NEW_TAG" >> $GITHUB_OUTPUT + fi shell: bash - name: Create and push new tag - if: ${{ !inputs.dry_run }} + if: ${{ !inputs.dry_run && inputs.channel == 'internal' }} run: | - git tag ${{ steps.calculate_new_tag.outputs.new_tag }} - git push origin ${{ steps.calculate_new_tag.outputs.new_tag }} + git tag ${{ steps.calculate_tags.outputs.tag_to_process }} + git push origin ${{ steps.calculate_tags.outputs.tag_to_process }} + + - name: Create and push final tag + if: ${{ !inputs.dry_run && inputs.channel != 'internal' }} + run: | + git tag ${{ steps.calculate_tags.outputs.final_tag }} ${{ steps.calculate_tags.outputs.tag_to_process }} + git push origin ${{ steps.calculate_tags.outputs.final_tag }} call-release-workflow: if: ${{ !inputs.dry_run && inputs.channel == 'internal' }} - needs: create-tag + needs: determine-tags uses: ./.github/workflows/release.yml with: - tag_name: ${{ needs.create-tag.outputs.new_tag }} + tag_name: ${{ needs.determine-tags.outputs.tag_to_process }} channel: ${{ inputs.channel }} base_version: ${{ inputs.base_version }} secrets: inherit call-promote-workflow: if: ${{ !inputs.dry_run && inputs.channel != 'internal' }} - needs: create-tag + needs: determine-tags uses: ./.github/workflows/promote.yml with: - tag_name: ${{ needs.create-tag.outputs.new_tag }} + tag_name: ${{ needs.determine-tags.outputs.tag_to_process }} + release_name: ${{ needs.determine-tags.outputs.release_name }} + final_tag: ${{ needs.determine-tags.outputs.final_tag }} channel: ${{ inputs.channel }} base_version: ${{ inputs.base_version }} secrets: inherit diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index c7d1f80cc..6edac0c69 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -11,6 +11,14 @@ on: description: 'The tag that triggered the release' required: true type: string + release_name: + description: 'The desired name for the GitHub release' + required: true + type: string + final_tag: + description: 'The final tag for the release' + required: true + type: string channel: description: 'The channel to promote to' required: true @@ -90,17 +98,17 @@ jobs: package-name: 'com.geeksville.mesh' from-track: 'internal' to-track: ${{ inputs.channel == 'closed' && 'NewAlpha' || (inputs.channel == 'open' && 'beta' || 'production') }} - user-fraction: ${{ inputs.channel == 'production' && '0.1' || (inputs.channel == 'open' && '0.5') || '1.0' }} + user-fraction: ${{ (inputs.channel == 'production' && '0.1') || (inputs.channel == 'open' && '0.5') || '1.0' }} update-github-release: runs-on: ubuntu-latest needs: [ prepare-build-info, promote-release ] steps: - - name: Update GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ inputs.tag_name }} - name: ${{ inputs.tag_name }} (${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}) - generate_release_notes: true - draft: false - prerelease: ${{ inputs.channel != 'production' }} \ No newline at end of file + - name: Update GitHub Release with gh CLI + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release edit ${{ inputs.tag_name }} \ + --tag ${{ inputs.final_tag }} \ + --title "${{ inputs.release_name }} (${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }})" \ + --prerelease=${{ inputs.channel != 'production' }}