# Releasing
Releases are published from GitHub Actions
([`.github/workflows/publish.yml`](.github/workflows/publish.yml)). The workflow
runs every release check, uploads the crate, verifies the archive served by
crates.io, and only then creates the matching `vX.Y.Z` tag and GitHub release.
Do not run `cargo publish` or create the tag locally.
`kotlin-codegen` is a zero-dependency library, so its `Cargo.lock` is not
committed and the release checks intentionally do not use `--locked`.
`kotlin-codegen` must be published before `prebindgen-jni`, which depends on it.
## First publication: 0.1.0
Trusted Publishing cannot create a crate that does not exist on crates.io yet.
The first publication therefore uses a scoped crates.io API token while still
running the complete release from CI.
### Configure crates.io and GitHub
1. Sign in to crates.io with the account that will own `kotlin-codegen`. Verify
the account email if crates.io requests it.
2. Create a crates.io API token that is allowed to publish a new crate. Give it
a short expiration because it is needed only for the first release.
3. In **GitHub → kotlin-codegen → Settings → Environments**, create an
environment named `crates-io`.
4. Add the API token to that environment as a secret named
`CARGO_REGISTRY_TOKEN`. Do not set the `CRATES_IO_TRUSTED_PUBLISHING`
variable yet.
5. Optionally add a required reviewer to the environment so publication needs
explicit approval.
### Prepare and publish 0.1.0
1. Confirm that `Cargo.toml` contains version `0.1.0` and that `CHANGELOG.md`
contains a `## 0.1.0` section.
2. Run the release checks locally:
```console
cargo fmt --all -- --check \
--config "unstable_features=true,imports_granularity=Crate,group_imports=StdExternalCrate"
cargo clippy --all-targets --all-features -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps
cargo test --all-targets --all-features
cargo package
```
3. Merge the release-preparation PR into `main` only after CI passes.
4. Optionally rehearse first: open **Actions → Publish to crates.io → Run
workflow**, select `main`, enter `0.1.0`, and enable **dry_run**. This runs
every check and `cargo publish --dry-run` without publishing or tagging.
5. Open **Actions → Publish to crates.io → Run workflow**.
6. Select `main`, enter `0.1.0` without a `v` prefix, leave **dry_run**
unchecked, and run the workflow.
7. Approve the `crates-io` environment deployment if approval is required.
8. Confirm that the workflow created all three release artifacts:
- `kotlin-codegen` 0.1.0 on crates.io;
- tag `v0.1.0` pointing to the published commit;
- GitHub release `v0.1.0`.
The workflow verifies that the downloaded crates.io archive records the same
Git commit before it creates the tag. If publication succeeds but a later step
fails, rerun the workflow with `0.1.0`; it resumes without uploading the version
again.
## Switch to Trusted Publishing after 0.1.0
Once 0.1.0 exists on crates.io:
1. Open the `kotlin-codegen` crate's **Settings → Trusted Publishing** page.
2. Add a GitHub Actions publisher with these exact values:
- repository owner: `milyin`
- repository: `kotlin-codegen`
- workflow: `publish.yml`
- environment: `crates-io`
3. In the GitHub `crates-io` environment, add the variable
`CRATES_IO_TRUSTED_PUBLISHING` with the value `true`.
4. Delete the `CARGO_REGISTRY_TOKEN` secret from the environment.
5. After one later release succeeds through Trusted Publishing, optionally
enable Trusted-Publishing-Only mode in the crate settings.
Later publication jobs exchange GitHub's OIDC identity for a short-lived
crates.io token. No permanent crates.io credential remains in GitHub.
## Publish a later version
1. In a release-preparation PR:
- update the version in `Cargo.toml`;
- add the matching `## <version>` section to `CHANGELOG.md`;
- update the README and API documentation as needed;
- run the local release checks shown above.
2. Merge the PR into `main` after CI passes.
3. Run **Actions → Publish to crates.io** from `main` with the exact manifest
version, without the `v` prefix. Enable **dry_run** first if you want a
rehearsal.
4. Confirm the crates.io version, `v<version>` tag, GitHub release, and docs.rs
documentation.
## Recover from a partial release
Rerunning the workflow with the same version is safe:
- If crates.io does not contain the version, the workflow publishes it.
- If it is already published from the current commit, publication is skipped
and release creation resumes.
- If it was published from another commit, the workflow stops.
- An existing tag is reused only if it points to the published commit.
Published versions cannot be replaced. Correct a bad release by publishing a
new version; never move a published version's tag.