The release.sh script automates dual-channel releases for the Yakcov library. It reads compose-releases.toml to determine which Compose Multiplatform versions to target, then builds and publishes an artifact for each channel to Maven Central.
For each channel defined in compose-releases.toml:
- Determines the next tag by analyzing existing git tags and incrementing
- Cleans build state (Gradle build +
kotlin-js-store) to avoid stale JS/Wasm caches - Patches
gradle/libs.versions.tomlwith the channel's compose, material3, kotlin and jvm-target values - Builds and publishes to Maven Central via Gradle with
-PpublishVersion=$TAG - Creates and pushes the git tag to the remote repository
- Restores
libs.versions.tomlto its original state
Defines the release channels at the project root:
[stable]
compose = "1.11.1"
compose-material3 = "1.11.0-alpha07"
xcode = "26.3" # Compose 1.11 iOS needs a newer Xcode than the runner default
[next]
track = "prerelease"
compose = "1.12.0-alpha01"
compose-material3 = "1.12.0-alpha01"
kotlin = "2.4.0" # Compose 1.12 bundles the compose-compiler with Kotlin 2.4.0
xcode = "26.3"| Key | Required | Description |
|---|---|---|
compose |
Yes | Compose Multiplatform plugin + dependency version |
compose-material3 |
Yes | Material3 artifact version (often differs from compose) |
kotlin |
No | Kotlin version override. Omit to inherit from libs.versions.toml |
jvm-target |
No | Android JVM bytecode target override. Omit to inherit jvmTarget from libs.versions.toml |
track |
No | Upstream channel the version tracker follows: stable or prerelease. Defaults to stable for [stable], prerelease otherwise |
xcode |
No | Xcode version for the Apple CI/publish job. Omit to use the runner default |
Comment out a section to skip that channel (e.g. retire [next] to release only stable). Note that compose is shared but AGP and the Gradle wrapper are not per-channel — a channel needing a newer AGP/compileSdk (as Compose 1.12 does: AGP ≥ 9.1.0 / compileSdk 37) raises the floor for the whole repo. See CLAUDE.md → Dual-Channel Releases → Toolchain coupling.
- Yakcov signing keys on your machine (required for Maven Central publishing)
- Run from the project root directory
- Push permissions to the repository
# Release all channels (default)
./scripts/release.sh
# Release a specific channel only
./scripts/release.sh --channel stable
./scripts/release.sh --channel next
# Preview what would happen without making changes
./scripts/release.sh --dry-run
# Combine flags
./scripts/release.sh --channel next --dry-run[INFO] === Release Plan ===
[stable] compose=1.11.1 material3=1.11.0-alpha07 kotlin=<inherited>
[stable] tag=1.11.1
[next] compose=1.12.0-alpha01 material3=1.12.0-alpha01 kotlin=2.4.0
[next] tag=1.12.0-alpha01
Continue with release? (y/N):
| Channel | First release | Subsequent releases |
|---|---|---|
| stable | 1.11.1 |
1.11.1-1, 1.11.1-2 |
| next | 1.12.0-alpha01 |
1.12.0-alpha01-1, 1.12.0-alpha01-2 |
The script automatically detects existing tags and increments.
The -N suffix is for sequential re-releases of one channel. Two channels pointed at one
compose version are refused outright — by the release plan and by CI's Build-Matrix, and
regardless of --channel, since the collision is a property of the file rather than of the
channels you selected. Recover by giving them distinct versions or commenting a section out.
Separately, and for a different reason: when upstream has no prerelease ahead of stable, the
tracker holds [next] at its current version, leaving it behind stable. Releasing it then
ships a superseded artifact, so release only stable (--channel stable) — no collision is
involved.
The CI workflow (.github/workflows/checks.yml) automatically tests against all channels defined in compose-releases.toml. Each test job (JS, JVM, Apple) runs once per channel using a matrix strategy.
- If the build fails for a channel, no tag is pushed (clean rollback)
- If one channel succeeds and another fails, the script reports which failed
- Re-run with
--channel <name>to retry only the failed channel
Test the release logic without making any changes:
./scripts/test-release-logic.shThis validates: TOML parsing, channel selection (including the distinct-version guard), tag computation, version patching, and restoration.
To publish manually without the script:
./gradlew :library:publishAndReleaseToMavenCentral --no-configuration-cache -PpublishVersion=1.11.1A GitHub Actions workflow allows releasing from CI instead of locally.
Your local machine uses ~/.gradle/gradle.properties for Maven Central credentials and GPG signing. CI needs the same values as GitHub secrets.
-
Create a GitHub environment called
maven-centralat:https://github.com/chrisjenx/yakcov/settings/environments -
Add these secrets to the
maven-centralenvironment, using the values from your~/.gradle/gradle.properties:Secret gradle.properties equivalent Description MAVEN_CENTRAL_USERNAMEmavenCentralUsernameSonatype Central Portal user token username MAVEN_CENTRAL_PASSWORDmavenCentralPasswordSonatype Central Portal user token password SIGNING_KEYn/a (file-based locally) Run: gpg --export-secret-keys --armor <key-id>(full output)SIGNING_KEY_IDsigning.keyIdLast 8 hex characters of your GPG key ID SIGNING_KEY_PASSWORDsigning.passwordGPG key passphrase Note: Locally you use
signing.secretKeyRingFileto point at a GPG keyring file. CI uses the in-memory key (signingInMemoryKey) instead — this is the ASCII-armored export of the same key.
From GitHub UI:
- Go to Actions → "Release" workflow
- Click "Run workflow"
- Select channel (
all,stable, ornext) - Optionally check "Dry run" to build without publishing
- Click "Run workflow"
From CLI:
# Release all channels
gh workflow run release.yml -f channel=all
# Release stable only
gh workflow run release.yml -f channel=stable
# Dry run
gh workflow run release.yml -f channel=all -f dry-run=true- Run the script from the project root
- Check if the Compose/Kotlin version combination is compatible
- Try running
./gradlew buildwith the patched versions manually - Re-run with
--channel <name>after fixing
- Ensure signing keys are configured
- Check network connectivity
- Verify Maven Central credentials
| File | Purpose |
|---|---|
compose-releases.toml |
Defines Compose version channels |
scripts/release.sh |
Main dual-channel release script |
scripts/test-release-logic.sh |
Non-destructive test script |
RELEASE_SCRIPT.md |
This documentation |