Maintainer notes for cutting releases of metro-extensions to Maven Central.
Group: com.plusmobileapps.metro-extensions
| Module | Artifact ID |
|---|---|
:lib:assisted-factory:runtime |
assisted-factory-runtime |
:lib:assisted-factory:compiler |
assisted-factory-compiler |
The version for all assisted-factory artifacts is controlled by the assistedFactory key in gradle/libs.versions.toml. Each extension added in the future should follow the same convention: a single shared version key in the catalog referenced from the module's mavenPublishing { coordinates(...) } block.
The project publishes through the Central Portal, not the legacy OSSRH/S01 host. You need:
- A Sonatype Central Portal account with the
com.plusmobileappsnamespace verified. - A user token generated from the Central Portal UI (token name + secret — these become
MAVEN_CENTRAL_USERNAME/MAVEN_CENTRAL_PASSWORD, NOT your portal login).
Maven Central requires signed artifacts. Generate an ASCII-armored GPG key and export it:
gpg --full-generate-key # RSA 4096, no expiry recommended
gpg --list-secret-keys --keyid-format LONG # grab the long key id
gpg --armor --export-secret-keys <KEY_ID> # ASCII-armored secret keyDistribute the public half to a keyserver so the Central Portal validator can find it:
gpg --keyserver keyserver.ubuntu.com --send-keys <KEY_ID>Put your publishing credentials in your user-home Gradle properties file at ~/.gradle/gradle.properties — NOT in this repo's gradle.properties (committed) and NOT in local.properties (Gradle does not load it as project properties; AGP reads it only for sdk.dir).
The vanniktech maven-publish plugin reads these property names directly (no ORG_GRADLE_PROJECT_ prefix when stored in a properties file — that prefix is only for environment variables):
# ~/.gradle/gradle.properties
mavenCentralUsername=<Central Portal user-token name>
mavenCentralPassword=<Central Portal user-token secret>
signingInMemoryKeyId=<last 8 chars of the GPG key id>
signingInMemoryKeyPassword=<GPG key passphrase>
signingInMemoryKey=<ASCII-armored secret key>The signingInMemoryKey value is the entire -----BEGIN PGP PRIVATE KEY BLOCK-----…-----END PGP PRIVATE KEY BLOCK----- block. Two formats work:
- Single line with
\nliterals: replace every newline with the two characters\nso the whole thing fits on one line. - Multi-line with backslash continuations: end every line of the armored block (except the last) with a trailing
\so Java'sPropertiesparser folds them into one logical value.
Generate the export with:
gpg --armor --export-secret-keys <LONG_KEY_ID>Never put these in
local.properties, the repo'sgradle.properties, or anywhere git-tracked. Treat~/.gradle/gradle.propertiesas machine-local secrets.
Set the following on the repo (Settings → Secrets and variables → Actions):
| Secret | Value |
|---|---|
MAVEN_CENTRAL_USERNAME |
Central Portal user-token name |
MAVEN_CENTRAL_PASSWORD |
Central Portal user-token secret |
SIGNING_KEY_ID |
Last 8 chars of the GPG key id |
SIGNING_PASSWORD |
Passphrase for the GPG key |
GPG_KEY_CONTENTS |
ASCII-armored secret key (entire -----BEGIN…-----END----- block) |
The CI workflow at .github/workflows/publish-libraries.yml exports each as an ORG_GRADLE_PROJECT_<name> environment variable — Gradle maps those to the same project property names the plugin reads (mavenCentralUsername, signingInMemoryKey, etc.).
Before tagging a release, verify the artifacts publish to your local Maven repo:
./gradlew publishToMavenLocal --no-configuration-cacheInspect ~/.m2/repository/com/plusmobileapps/metro-extensions/ for the expected per-target artifacts (-jvm, -android, -iosarm64, etc. for the runtime; a single jar for the compiler). Confirm .asc signature files appear alongside each artifact, and that gpg --verify <file>.asc <file> passes.
For a full pre-release rehearsal that exercises uploading without auto-releasing the deployment, run:
./gradlew publishAllPublicationsToMavenCentralRepository --no-configuration-cacheThis stages artifacts in a Central Portal deployment but does not release them — useful for catching POM/signing problems.
- Bump
assistedFactoryingradle/libs.versions.toml(semver —0.1.0→0.2.0for new extensions,0.1.1for fixes). - Commit + push to
main. - Create a GitHub release with tag
v<version>(e.g.v0.2.0). Mark as pre-release for-SNAPSHOT/-alphaversions if desired — the workflow fires on bothreleasedandprereleased. - The
Publishworkflow (.github/workflows/publish-libraries.yml) runs./gradlew publishToMavenCentral, which uploads + automatically releases the deployment via the Central Portal API. - Verify on https://central.sonatype.com/ → namespace
com.plusmobileapps.metro-extensions. New versions usually appear in Maven Central search within ~30 minutes.
When introducing a new extension (e.g. :lib:my-extension:{runtime,compiler}):
- Add a version key to
gradle/libs.versions.toml(e.g.myExtension = "0.1.0"). - In each module's
build.gradle.kts, applyalias(libs.plugins.mavenPublish)and add amavenPublishing { … }block — copy fromlib/assisted-factory/{runtime,compiler}/build.gradle.ktsand adjust coordinates / POM name / description. - No workflow changes needed —
publishToMavenCentralaggregates every publishable subproject.