From 7f3bd22f1e536b19da891c6698ae41d2712ed9ab Mon Sep 17 00:00:00 2001 From: Rasmus Ros Date: Thu, 13 Aug 2026 08:48:57 +0200 Subject: [PATCH 1/2] ci: publish a snapshot on every push to main --- .github/workflows/release.yml | 54 +++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 017bde3..316827b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,19 +2,34 @@ 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: @@ -29,14 +44,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 + if: env.IS_SNAPSHOT == 'false' run: ./gradlew --no-daemon 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,7 +88,7 @@ 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 }} @@ -55,7 +97,7 @@ jobs: run: ./gradlew --no-daemon 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 }} @@ -64,6 +106,7 @@ jobs: run: ./gradlew --no-daemon 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 +115,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 }} From 1b904c3f0c496fc84139685749521f50043879f3 Mon Sep 17 00:00:00 2001 From: Rasmus Ros Date: Thu, 13 Aug 2026 08:55:05 +0200 Subject: [PATCH 2/2] ci: read the gradle caches in the release job --- .github/workflows/release.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 316827b..8893123 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,14 @@ jobs: 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 @@ -75,7 +82,7 @@ jobs: - name: Build and Test if: env.IS_SNAPSHOT == 'false' - run: ./gradlew --no-daemon build -PciVersion=${{ env.RELEASE_VERSION }} + run: ./gradlew build -PciVersion=${{ env.RELEASE_VERSION }} - name: Upload test reports if: always() && env.IS_SNAPSHOT == 'false' @@ -94,7 +101,7 @@ jobs: 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: env.IS_SNAPSHOT == 'true' @@ -103,7 +110,7 @@ jobs: 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'