diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 017bde3..8893123 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,25 +2,47 @@ name: release on: push: + branches: + - main tags: - 'v*' workflow_dispatch: + inputs: + dryRun: + description: Run the release build and publish nothing + type: boolean + default: false permissions: contents: write +# Superseded snapshot runs are pointless, but a tag publish must never be cancelled. +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: ${{ github.ref_type != 'tag' }} + jobs: publish: runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v6 + with: + # Tags are needed to derive the next snapshot version on a main push. + fetch-depth: 0 - uses: actions/setup-java@v5 with: distribution: temurin java-version: 25 - cache: gradle + + # Reads the build and configuration caches build.yml writes, read-only so release runs + # never seed them. + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v6 + with: + cache-read-only: true + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - name: Cache Kotlin/Native toolchain uses: actions/cache@v5 @@ -29,14 +51,41 @@ jobs: key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }} restore-keys: ${{ runner.os }}-konan- - - name: Extract Version - run: echo "RELEASE_VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV + # A tag publishes that exact version as a release. Any other ref publishes a snapshot of the + # next patch, so main always has a consumable build. A dry run takes the release path as far + # as the tests and stops, so the tag path can be exercised on demand. + - name: Resolve Version + run: | + next_patch() { + # Release tags only; a prerelease tag must not advance the line. + local last base major minor patch + last=$(git tag --list 'v*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n1) + base="${last:-v0.0.0}" + base="${base#v}" + IFS=. read -r major minor patch <<<"$base" + echo "${major:-0}.${minor:-0}.$(( ${patch:-0} + 1 ))" + } + if [[ "${{ inputs.dryRun }}" == "true" ]]; then + version="$(next_patch)" + echo "DRY_RUN=true" >> "$GITHUB_ENV" + elif [[ "$GITHUB_REF_TYPE" == "tag" ]]; then + version="${GITHUB_REF_NAME#v}" + else + version="$(next_patch)-SNAPSHOT" + fi + echo "RELEASE_VERSION=$version" >> "$GITHUB_ENV" + if [[ "$version" == *-SNAPSHOT ]]; then + echo "IS_SNAPSHOT=true" >> "$GITHUB_ENV" + else + echo "IS_SNAPSHOT=false" >> "$GITHUB_ENV" + fi - name: Build and Test - run: ./gradlew --no-daemon build -PciVersion=${{ env.RELEASE_VERSION }} + if: env.IS_SNAPSHOT == 'false' + run: ./gradlew build -PciVersion=${{ env.RELEASE_VERSION }} - name: Upload test reports - if: always() + if: always() && env.IS_SNAPSHOT == 'false' uses: actions/upload-artifact@v7 with: name: test-reports @@ -46,24 +95,25 @@ jobs: if-no-files-found: ignore - name: Publish to Maven Central (Portal) - if: ${{ !contains(env.RELEASE_VERSION, '-') }} + if: env.IS_SNAPSHOT == 'false' && env.DRY_RUN != 'true' env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USER }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} - run: ./gradlew --no-daemon publishToMavenCentral -PciVersion=${{ env.RELEASE_VERSION }} + run: ./gradlew publishToMavenCentral -PciVersion=${{ env.RELEASE_VERSION }} - name: Publish to Sonatype Snapshots - if: ${{ contains(env.RELEASE_VERSION, '-') }} + if: env.IS_SNAPSHOT == 'true' env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.CENTRAL_PORTAL_USER }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} - run: ./gradlew --no-daemon publishAllPublicationsToSonatypeSnapshotsRepository -PciVersion=${{ env.RELEASE_VERSION }} + run: ./gradlew publishAllPublicationsToSonatypeSnapshotsRepository -PciVersion=${{ env.RELEASE_VERSION }} - name: Detect pre-release + if: github.ref_type == 'tag' && env.IS_SNAPSHOT == 'false' run: | if [[ "$RELEASE_VERSION" == *"-"* ]]; then echo "IS_PRERELEASE=true" >> "$GITHUB_ENV" @@ -72,6 +122,7 @@ jobs: fi - name: Create GitHub Release + if: github.ref_type == 'tag' && env.IS_SNAPSHOT == 'false' uses: softprops/action-gh-release@v2 with: prerelease: ${{ env.IS_PRERELEASE }}