| name | sling-release |
| description | Automates releasing an Apache Sling project end-to-end using Maven and the sling-cli Docker tool. Use when the user wants to release a Sling project, start a release, perform any step of the Apache Sling release process, or asks about releasing/voting/promoting a Sling module. |
| tools | Bash, Read, Edit, Write |
This skill releases an Apache Sling module end-to-end by combining Maven steps (run in the
project being released) with the apache/sling-cli Docker tool (this repo) for the
Nexus/vote/finalize steps.
Overview
Three phases:
- Stage — Maven prepares the release and stages signed artifacts to Nexus.
- Vote — close the staging repo, verify, send the
[VOTE] email, wait 72h, tally.
- Finalize — after a passing vote: promote to Maven Central, update JIRA + Reporter, and (for
PMC members) publish to
dist.apache.org.
Prerequisites (verify before starting)
- Docker is available, and the
apache/sling-cli image is built/pulled.
~/.apache-committer (or any env file) with ASF credentials, passed to the container:
ASF_USERNAME=your-apache-id
ASF_PASSWORD=your-apache-password
- GPG signing key published to
keys.openpgp.org and added to the Sling KEYS file
(https://dist.apache.org/repos/dist/release/sling/KEYS).
~/.m2/settings.xml configured for maven-gpg-plugin 3.x (used by recent parent POMs). The
passphrase is read from a server whose id is gpg.passphrase (the gpg.passphraseServerId
default) and decrypted via settings-security.xml — not from a <gpg.passphrase> profile
property (that older approach is passed to gpg literally and fails):
<servers>
<server><id>apache.snapshots.https</id><username>ID</username><password>{ENC}</password></server>
<server><id>apache.releases.https</id><username>ID</username><password>{ENC}</password></server>
<server><id>gpg.passphrase</id><passphrase>{ENC}</passphrase></server>
</servers>
<profiles><profile>apache-release
loopback
YOUR_KEY_ID
smtp.gmail.com
~/.m2/settings-security.xml with the <master> password used to decrypt the above.
If any prerequisite is missing, stop and tell the user how to set it up before proceeding.
Running the CLI
Use the Docker image directly. A sling-cli shell alias may exist but usually includes -it (TTY),
which fails in non-interactive contexts like Claude Code — so do not rely on it:
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release <command> [options]
- Default mode is
DRY_RUN (shows what would happen). Add -x AUTO to execute, -x INTERACTIVE to confirm each step.
- Always run a DRY_RUN first for any command that sends mail or mutates Nexus/dist, show the user the output, then re-run with
-x AUTO.
~ does not expand inside quoted docker args — use $HOME.
Determining the Java version (Maven steps)
Build with the Java version required by the project's Sling parent POM (recent parents require Java
17). If mvnXX wrappers are absent, set JAVA_HOME explicitly to an installed JDK
(/usr/libexec/java_home -V to list).
Phase 1: Stage (Maven, in the project being released)
- Parent POM current? Confirm it's up to date and
mvn clean verify is green.
- Dry-run prepare, then clean. Verify only
<version>/<scm> differ in pom.xml.tag:
mvn release:prepare -DdryRun=true && mvn release:clean
- Deploy snapshot; confirm
META-INF/LICENSE + META-INF/NOTICE are inside the jar:
mvn deploy
- Prepare + perform (creates the tag, bumps to next SNAPSHOT, signs + stages to Nexus):
mvn release:prepare
mvn release:perform
Capture the staging repo id from a …/orgapachesling-NNNN line. If it scrolled off, find it with
release list (below).
Phase 2: Vote
2.0 — Find the staging repo id (if not captured)
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release list
Lists every staging repo with its [open]/[closed] state. A freshly staged repo is [open]; the
numeric suffix of orgapachesling-NNNN is the REPO_ID.
2.1 — Close the staging repository
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release close-staging -r <REPO_ID> -x AUTO
The description is auto-derived from the staged POM's <name> <version> (so it is correct even for an
open repo not yet in the Lucene index). After closing, the repo shows as [closed].
2.2 — Verify artifacts
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release verify -r <REPO_ID>
Confirm PGP signatures, SHA-1, MD5, and CI status all pass before voting.
2.3 — Send the vote email (dry-run first!)
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release prepare-email -r <REPO_ID>
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release prepare-email -r <REPO_ID> -x AUTO
2.4 — Wait 72h, then tally
At least 72 hours on dev@sling.apache.org and ≥3 binding (PMC) +1 votes are required.
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release tally-votes -r <REPO_ID>
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release tally-votes -r <REPO_ID> -x AUTO
PMC membership is auto-detected from your ASF id — no flag needed. If you are a PMC member the
result email says you will copy the release to the dist directory yourself; otherwise it asks a PMC
member to do the dist upload.
If the vote FAILS
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release drop -r <REPO_ID> -x AUTO
git push --delete origin <TAG_NAME>
git tag -d <TAG_NAME>
Phase 3: Finalize (after a passing vote)
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release finalize -r <REPO_ID> -x AUTO
Runs in order: promote to Maven Central → (if you are a PMC member) update dist.apache.org →
create next JIRA version & move unresolved issues → mark JIRA version released → update Apache
Reporter.
- PMC detection is automatic. A PMC member's run also publishes to
dist.apache.org; the previous
version to remove is deduced from the dist/release directory, so no --previous-version is
needed (override with --previous-version X.Y.Z only if necessary). A non-PMC run skips the dist
step (a PMC member handles it, as requested in the tally-votes email).
Update the website (optional)
docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli release update-local-site -r <REPO_ID>
Review the diff, then commit & push the sling-site changes separately.
Quick reference
<cli> = docker run --rm --env-file=$HOME/.apache-committer apache/sling-cli
| Command | When |
|---|
<cli> release list | List staging repos with [open]/[closed] state + description |
<cli> release close-staging -r <ID> -x AUTO | After mvn release:perform |
<cli> release verify -r <ID> | Before sending the vote email |
<cli> release prepare-email -r <ID> -x AUTO | Send the [VOTE] email |
<cli> release tally-votes -r <ID> -x AUTO | After 72h with ≥3 binding votes (PMC auto-detected) |
<cli> release finalize -r <ID> -x AUTO | All post-vote steps (dist included automatically for PMC) |
<cli> release promote -r <ID> -x AUTO | Promote to Maven Central (individual step) |
<cli> release update-dist -r <ID> -x AUTO | Update dist.apache.org (PMC only; prev version auto-deduced) |
<cli> release drop -r <ID> -x AUTO | Drop staging (failed vote / cleanup) |
<cli> release create-new-jira-version -r <ID> -x AUTO | Create next JIRA version |
<cli> release release-jira-version -r <ID> -x AUTO | Mark JIRA version released |
<cli> release update-reporter -r <ID> -x AUTO | Update Apache Reporter |
<cli> release update-local-site -r <ID> | Update JBake website content |
Execution notes
When this skill is invoked:
- Confirm which phase the user is starting from (Stage / Vote / Finalize / Cancel) and the
REPO_ID if past Phase 1.
- Verify the prerequisites above before any mutating step.
- For mail/Nexus/dist commands, run DRY_RUN first, show output, then
-x AUTO.
- On failure, diagnose (often a missing prereq or wrong
REPO_ID) and suggest a fix before retrying.
- Do not touch git state beyond what the documented steps require.