ci(release): refactor release workflow to be callable (#3330)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2025-10-04 12:13:05 -05:00 committed by GitHub
parent f2b4b87944
commit 015bf123b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 176 additions and 90 deletions

View file

@ -0,0 +1,77 @@
name: Create or Promote Release
on:
workflow_dispatch:
inputs:
base_version:
description: 'Base version for the release (e.g., 2.3.0)'
required: true
channel:
description: 'The channel to create a release for or promote to'
required: true
type: choice
options:
- internal
- closed
- open
- production
dry_run:
description: 'If true, calculates the tag but does not push it or start the release'
required: true
type: boolean
default: false
permissions:
contents: write
jobs:
create-tag:
runs-on: ubuntu-latest
outputs:
new_tag: ${{ steps.calculate_new_tag.outputs.new_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Calculate new release tag
id: calculate_new_tag
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 [ -z "$LATEST_TAG" ]; then
INCREMENT=1
else
INCREMENT=$(echo "$LATEST_TAG" | sed -n "s/.*-${CHANNEL}\.\([0-9]*\)/\1/p" | awk '{print $1+1}')
fi
NEW_TAG="v${BASE_VERSION}-${CHANNEL}.${INCREMENT}"
fi
echo "Calculated new tag: $NEW_TAG"
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT
shell: bash
- name: Create and push new tag
if: ${{ !inputs.dry_run }}
run: |
git tag ${{ steps.calculate_new_tag.outputs.new_tag }}
git push origin ${{ steps.calculate_new_tag.outputs.new_tag }}
call-release-workflow:
if: ${{ !inputs.dry_run }}
needs: create-tag
uses: ./.github/workflows/release.yml
with:
tag_name: ${{ needs.create-tag.outputs.new_tag }}
release_type: ${{ inputs.channel == 'internal' && 'internal' || 'promotion' }}
secrets: inherit

View file

@ -1,13 +1,38 @@
name: Make Release
on:
workflow_dispatch:
push:
tags:
- 'v*'
workflow_call:
inputs:
tag_name:
description: 'The tag that triggered the release'
required: true
type: string
release_type:
description: 'Type of release (internal or promotion)'
required: true
type: string
secrets:
GSERVICES:
required: true
KEYSTORE:
required: true
KEYSTORE_FILENAME:
required: true
KEYSTORE_PROPERTIES:
required: true
DATADOG_APPLICATION_ID:
required: true
DATADOG_CLIENT_TOKEN:
required: true
GOOGLE_MAPS_API_KEY:
required: true
GOOGLE_PLAY_JSON_KEY:
required: true
GRADLE_ENCRYPTION_KEY:
required: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ inputs.tag_name }}
cancel-in-progress: true
permissions:
@ -26,6 +51,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.tag_name }}
fetch-depth: 0
submodules: 'recursive'
- name: Set up JDK 21
@ -43,7 +69,7 @@ jobs:
- name: Determine Version Name from Tag
id: get_version_name
run: echo "APP_VERSION_NAME=$(echo ${GITHUB_REF_NAME#v} | sed 's/-.*//')" >> $GITHUB_OUTPUT
run: echo "APP_VERSION_NAME=$(echo ${{ inputs.tag_name }} | sed 's/-.*//' | sed 's/v//')" >> $GITHUB_OUTPUT
- name: Extract VERSION_CODE_OFFSET from config.properties
id: get_version_code_offset
@ -59,15 +85,16 @@ jobs:
VERSION_CODE=$((COMMIT_COUNT + OFFSET))
echo "versionCode=$VERSION_CODE" >> $GITHUB_OUTPUT
shell: bash
# This matches the reproducible versionCode strategy: versionCode = git commit count + offset
release-google:
runs-on: ubuntu-latest
needs: prepare-build-info
environment: Release
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.tag_name }}
fetch-depth: 0
submodules: 'recursive'
- name: Set up JDK 21
@ -76,7 +103,6 @@ jobs:
java-version: '21'
distribution: 'jetbrains'
- name: Setup Gradle
if: contains(github.ref_name, '-internal')
uses: gradle/actions/setup-gradle@v5
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
@ -95,7 +121,7 @@ jobs:
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
run: |
rm -f ./app/google-services.json # Ensure clean state
rm -f ./app/google-services.json
echo $GSERVICES > ./app/google-services.json
echo $KEYSTORE | base64 -di > ./app/$KEYSTORE_FILENAME
echo "$KEYSTORE_PROPERTIES" > ./keystore.properties
@ -113,12 +139,11 @@ jobs:
- name: Determine Fastlane Lane
id: fastlane_lane
run: |
TAG_NAME="${{ github.ref_name }}"
if [[ "$TAG_NAME" == *"-internal"* ]]; then
if [[ "${{ inputs.tag_name }}" == *"-internal"* ]]; then
echo "lane=internal" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-closed"* ]]; then
elif [[ "${{ inputs.tag_name }}" == *"-closed"* ]]; then
echo "lane=closed" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-open"* ]]; then
elif [[ "${{ inputs.tag_name }}" == *"-open"* ]]; then
echo "lane=open" >> $GITHUB_OUTPUT
else
echo "lane=production" >> $GITHUB_OUTPUT
@ -131,7 +156,6 @@ jobs:
run: bundle exec fastlane ${{ steps.fastlane_lane.outputs.lane }}
- name: Upload Google AAB artifact
if: contains(github.ref_name, '-internal')
uses: actions/upload-artifact@v4
with:
name: google-aab
@ -139,7 +163,6 @@ jobs:
retention-days: 1
- name: Upload Google APK artifact
if: contains(github.ref_name, '-internal')
uses: actions/upload-artifact@v4
with:
name: google-apk
@ -147,7 +170,6 @@ jobs:
retention-days: 1
- name: Attest Google artifacts provenance
if: contains(github.ref_name, '-internal')
uses: actions/attest-build-provenance@v3
with:
subject-path: |
@ -155,13 +177,14 @@ jobs:
app/build/outputs/apk/google/release/app-google-release.apk
release-fdroid:
if: contains(github.ref_name, '-internal')
runs-on: ubuntu-latest
needs: prepare-build-info
environment: Release
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ inputs.tag_name }}
fetch-depth: 0
submodules: 'recursive'
- name: Set up JDK 21
@ -210,41 +233,26 @@ jobs:
with:
subject-path: app/build/outputs/apk/fdroid/release/app-fdroid-release.apk
create-internal-release:
github-release:
runs-on: ubuntu-latest
needs: [prepare-build-info, release-google, release-fdroid]
if: contains(github.ref_name, '-internal')
environment: Release
steps:
- name: Download all artifacts
uses: actions/download-artifact@v5
with:
path: ./artifacts
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
name: ${{ github.ref_name }}
generate_release_notes: true
files: ./artifacts/*/*
draft: true
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
promote-release:
runs-on: ubuntu-latest
needs: [prepare-build-info, release-google]
if: "!contains(github.ref_name, '-internal')"
steps:
- name: Determine Release Properties
id: release_properties
run: |
TAG_NAME="${{ github.ref_name }}"
if [[ "$TAG_NAME" == *"-closed"* ]]; then
if [[ "${{ inputs.release_type }}" == "internal" ]]; then
echo "draft=true" >> $GITHUB_OUTPUT
echo "prerelease=true" >> $GITHUB_OUTPUT
elif [[ "${{ inputs.tag_name }}" == *"-closed"* ]]; then
echo "draft=false" >> $GITHUB_OUTPUT
echo "prerelease=true" >> $GITHUB_OUTPUT
elif [[ "$TAG_NAME" == *"-open"* ]]; then
elif [[ "${{ inputs.tag_name }}" == *"-open"* ]]; then
echo "draft=false" >> $GITHUB_OUTPUT
echo "prerelease=true" >> $GITHUB_OUTPUT
else
@ -252,12 +260,12 @@ jobs:
echo "prerelease=false" >> $GITHUB_OUTPUT
fi
- name: Update GitHub Release
- name: Create or Update GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
name: ${{ github.ref_name }}
tag_name: ${{ inputs.tag_name }}
name: ${{ inputs.tag_name }}
generate_release_notes: true
files: ./artifacts/*/*
draft: ${{ steps.release_properties.outputs.draft }}
prerelease: ${{ steps.release_properties.outputs.prerelease }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}