|
| 1 | +# Releasing to Maven Central |
| 2 | + |
| 3 | +This document covers how to create and publish a new release of the ID.me Auth Sample Code SDK to Maven Central and GitHub Packages. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The release process is fully automated via the [`release.yml`](../.github/workflows/release.yml) GitHub Actions workflow. A single manual trigger: |
| 8 | + |
| 9 | +1. Validates the version and checks for tag conflicts |
| 10 | +2. Builds the AAR and all Maven artifacts |
| 11 | +3. Generates SLSA build provenance attestations |
| 12 | +4. Publishes to both GitHub Packages and Maven Central (Sonatype OSSRH) |
| 13 | +5. Creates and pushes a git tag |
| 14 | +6. Creates a GitHub Release with the AAR and attestation bundle |
| 15 | + |
| 16 | +**Maven coordinates:** `com.idmelabs.auth:android-auth-sample-code:<version>` |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Prerequisites |
| 21 | + |
| 22 | +Before triggering a release, confirm the following are in place. |
| 23 | + |
| 24 | +### GitHub Secrets |
| 25 | + |
| 26 | +All secrets must be configured under the `release` GitHub Actions environment (not the default repository secrets). Navigate to **Settings → Environments → release** to manage them. |
| 27 | + |
| 28 | +| Secret | Description | |
| 29 | +|---|---| |
| 30 | +| `SONATYPE_USERNAME` | Sonatype Central Portal account username | |
| 31 | +| `SONATYPE_PASSWORD` | Sonatype Central Portal account password or token | |
| 32 | +| `SIGNING_KEY_ID` | GPG key ID (last 8 characters of the key fingerprint) | |
| 33 | +| `SIGNING_KEY` | GPG private key in ASCII-armored format | |
| 34 | +| `SIGNING_PASSWORD` | Passphrase for the GPG key | |
| 35 | + |
| 36 | +`GITHUB_TOKEN` is provided automatically by GitHub Actions and does not need to be configured manually. |
| 37 | + |
| 38 | +### GPG Key Setup |
| 39 | + |
| 40 | +If a GPG key has not been created yet: |
| 41 | + |
| 42 | +```bash |
| 43 | +# Generate a new GPG key (use RSA 4096, no expiry) |
| 44 | +gpg --full-generate-key |
| 45 | + |
| 46 | +# List keys to find your key ID |
| 47 | +gpg --list-secret-keys --keyid-format LONG |
| 48 | + |
| 49 | +# Export the private key for the SIGNING_KEY secret |
| 50 | +gpg --armor --export-secret-keys <KEY_ID> |
| 51 | + |
| 52 | +# Publish the public key to a keyserver so Maven Central can verify signatures |
| 53 | +gpg --keyserver keyserver.ubuntu.com --send-keys <KEY_ID> |
| 54 | +``` |
| 55 | + |
| 56 | +The `SIGNING_KEY_ID` is the **last 8 characters** of the full fingerprint shown by `--list-secret-keys`. |
| 57 | + |
| 58 | +### Sonatype Account |
| 59 | + |
| 60 | +Publishing to Maven Central requires a Sonatype account with publishing rights for the `com.idmelabs.auth` namespace. If you are setting this up for the first time, refer to the [Sonatype Central Portal documentation](https://central.sonatype.org/register/central-portal/) to register and claim the namespace. |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## Triggering a Release |
| 65 | + |
| 66 | +1. Go to the **Actions** tab of the repository on GitHub. |
| 67 | +2. Select the **Release Auth Sample** workflow from the left sidebar. |
| 68 | +3. Click **Run workflow**. |
| 69 | +4. Fill in the inputs: |
| 70 | + - **SDK Version** (required): The semantic version to release, e.g. `1.2.0` or `1.2.0-beta.1`. |
| 71 | + - **Make draft release** (optional): Check this box to create a draft GitHub Release (useful for review before publishing). |
| 72 | +5. Click **Run workflow** to start the job. |
| 73 | + |
| 74 | +### Version Format |
| 75 | + |
| 76 | +Versions must follow semantic versioning: `MAJOR.MINOR.PATCH` or `MAJOR.MINOR.PATCH-PRERELEASE`. |
| 77 | + |
| 78 | +Valid examples: |
| 79 | +- `1.0.0` |
| 80 | +- `2.1.3` |
| 81 | +- `1.0.0-beta.1` |
| 82 | +- `1.0.0-rc.2` |
| 83 | + |
| 84 | +The workflow will fail early if the version does not match this format or if the tag `v<version>` already exists. |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## What the Workflow Does |
| 89 | + |
| 90 | +### Step-by-Step |
| 91 | + |
| 92 | +1. **Checkout** — Full git history is fetched (`fetch-depth: 0`) to support tagging. |
| 93 | +2. **Environment setup** — JDK 17 (Temurin), Android SDK, and Gradle are configured. |
| 94 | +3. **Version validation** — The version string is validated against the semver regex and checked for existing tags. |
| 95 | +4. **Build release AAR** — Runs `./gradlew :sdk:assembleRelease -PreleaseVersion=<version>`. Output: `sdk/build/outputs/aar/sdk-release.aar`. |
| 96 | +5. **Build Maven artifacts locally** — Runs `./gradlew :sdk:publishReleasePublicationToMavenLocalRepository -PreleaseVersion=<version>`. Produces POM, AAR, sources JAR, and Dokka javadoc JAR in `~/.m2`. |
| 97 | +6. **Generate attestations** — SLSA build provenance is generated for both the release AAR and all Maven artifacts using `actions/attest-build-provenance`. |
| 98 | +7. **Publish to GitHub Packages** — All Maven artifacts (POM, AAR, module metadata, attestation bundle) are uploaded via the GitHub Packages Maven registry API. |
| 99 | +8. **Publish to Maven Central** — Runs: |
| 100 | + ``` |
| 101 | + ./gradlew :sdk:publishReleasePublicationToSonatypeRepository \ |
| 102 | + closeAndReleaseSonatypeStagingRepository \ |
| 103 | + -PreleaseVersion=<version> |
| 104 | + ``` |
| 105 | + This publishes signed artifacts to Sonatype staging and then closes and releases the staging repository to Maven Central. |
| 106 | +9. **Create git tag** — Tags the current commit as `v<version>` and pushes to `origin`. |
| 107 | +10. **Create GitHub Release** — A release is created with the AAR and SLSA attestation bundle attached. |
| 108 | + |
| 109 | +### Published Artifacts |
| 110 | + |
| 111 | +For version `1.2.0`, the following files are published: |
| 112 | + |
| 113 | +``` |
| 114 | +com/idmelabs/auth/android-auth-sample-code/1.2.0/ |
| 115 | +├── android-auth-sample-code-1.2.0.aar |
| 116 | +├── android-auth-sample-code-1.2.0.pom |
| 117 | +├── android-auth-sample-code-1.2.0-sources.jar |
| 118 | +├── android-auth-sample-code-1.2.0-javadoc.jar |
| 119 | +├── android-auth-sample-code-1.2.0.module |
| 120 | +└── android-auth-sample-code-1.2.0.intoto.jsonl (attestation bundle) |
| 121 | +``` |
| 122 | + |
| 123 | +All artifacts are signed with the configured GPG key. |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## Verifying a Release |
| 128 | + |
| 129 | +### Maven Central |
| 130 | + |
| 131 | +After the workflow completes, the release is available at: |
| 132 | + |
| 133 | +``` |
| 134 | +https://central.sonatype.com/artifact/com.idmelabs.auth/android-auth-sample-code |
| 135 | +``` |
| 136 | + |
| 137 | +Maven Central propagation typically takes 10–30 minutes after the staging repository is released. |
| 138 | + |
| 139 | +### GitHub Packages |
| 140 | + |
| 141 | +Artifacts are immediately available at: |
| 142 | + |
| 143 | +``` |
| 144 | +https://github.com/IDme/android-auth-sample-code/packages |
| 145 | +``` |
| 146 | + |
| 147 | +### SLSA Attestation |
| 148 | + |
| 149 | +To verify the build provenance of a downloaded artifact: |
| 150 | + |
| 151 | +```bash |
| 152 | +gh attestation verify android-auth-sample-code-<version>.aar --repo IDme/android-auth-sample-code |
| 153 | +``` |
| 154 | + |
| 155 | +--- |
| 156 | + |
| 157 | +## Troubleshooting |
| 158 | + |
| 159 | +### Tag already exists |
| 160 | + |
| 161 | +The workflow checks for existing tags before proceeding. If the tag `v<version>` already exists, the workflow will fail with: |
| 162 | + |
| 163 | +``` |
| 164 | +Tag v<version> already exists! |
| 165 | +``` |
| 166 | + |
| 167 | +Either choose a different version or, if the previous release failed partway through, delete the existing tag manually: |
| 168 | + |
| 169 | +```bash |
| 170 | +git push --delete origin v<version> |
| 171 | +git tag -d v<version> |
| 172 | +``` |
| 173 | + |
| 174 | +### Sonatype staging repository not closed |
| 175 | + |
| 176 | +If the `closeAndReleaseSonatypeStagingRepository` task fails, check the [Sonatype Central Portal](https://central.sonatype.com/) for the status of the staging repository. Common causes: |
| 177 | + |
| 178 | +- GPG signature validation failed (key not published to a keyserver) |
| 179 | +- Missing required POM fields |
| 180 | +- Artifact checksums mismatch |
| 181 | + |
| 182 | +### Signing failures |
| 183 | + |
| 184 | +If the build fails with a PGP signing error, verify that: |
| 185 | + |
| 186 | +- `SIGNING_KEY` contains the full ASCII-armored private key, including the `-----BEGIN PGP PRIVATE KEY BLOCK-----` header and footer |
| 187 | +- `SIGNING_KEY_ID` matches the key exported in `SIGNING_KEY` |
| 188 | +- `SIGNING_PASSWORD` is the correct passphrase for the key |
| 189 | + |
| 190 | +--- |
| 191 | + |
| 192 | +## Local Publishing (for testing) |
| 193 | + |
| 194 | +To test the build locally without publishing to any remote registry: |
| 195 | + |
| 196 | +```bash |
| 197 | +# Build the AAR |
| 198 | +./gradlew :sdk:assembleRelease -PreleaseVersion=1.0.0-SNAPSHOT |
| 199 | + |
| 200 | +# Publish to local Maven repository (~/.m2) |
| 201 | +./gradlew :sdk:publishReleasePublicationToMavenLocalRepository -PreleaseVersion=1.0.0-SNAPSHOT |
| 202 | +``` |
| 203 | + |
| 204 | +To consume the locally published artifact in another project, add `mavenLocal()` to the project's repository list: |
| 205 | + |
| 206 | +```kotlin |
| 207 | +repositories { |
| 208 | + mavenLocal() |
| 209 | + mavenCentral() |
| 210 | +} |
| 211 | +``` |
0 commit comments