Publish to Maven Central
Bleep ships a built-in bleep publish command. There is no script to
write, no plugin to import, your bleep.yaml declares what to publish
and bleep publish sonatype does it. PGP signing, Sonatype Central
upload, and dynver-based versioning from git tags are all wired in.
Prerequisites
- A working bleep project (see Your First Project).
- A Sonatype Central Portal account with a verified namespace (group ID).
- A PGP key pair. If you don't have one, the setup wizard below will generate one for you.
Step 1: Run the setup wizard
bleep publish setup
This is an interactive TUI that walks you through:
- Sonatype / Maven Central: generates a PGP key, exports the
passphrase to
~/.config/bleep/config.yaml, optionally publishes the public key to a key server. - GitHub Packages, GitLab Package Registry, and Google Artifact Registry, same, with provider-specific auth flows.
Skip this step if you already have credentials configured.
Step 2: Add publish metadata to bleep.yaml
Each project that should be published gets a publish: block. Maven
Central requires groupId, url, description, at least one developer,
and at least one license:
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M10
jvm:
name: graalvm-community:25.0.1
projects:
mylib:
platform:
name: jvm
publish:
groupId: io.github.myusername
url: https://github.com/myusername/mylib
description: A useful library that does useful things.
developers:
- id: myusername
name: My Name
url: https://github.com/myusername
licenses:
- name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.txt
sonatypeCredentialHost: central.sonatype.com
Field reference:
| field | required | notes |
|---|---|---|
enabled | no | defaults to true when publish is present. Set to false on a project that inherits a publish block from a template but shouldn't itself be published (e.g. a scripts module). |
groupId | yes | Maven group, e.g. io.github.myusername. Must match your verified Sonatype namespace. |
url | for Central | Project homepage. |
description | for Central | One-line summary. |
developers | for Central | List of { id, name, url }. |
licenses | for Central | List of { name, url, distribution? }. |
organization | optional | Organization name (rendered as <organization> in the POM). |
sonatypeProfileName | optional | Defaults to groupId. Override if your Sonatype profile name differs from your group. |
sonatypeCredentialHost | optional | Defaults to central.sonatype.com. Set to oss.sonatype.org if you're still on legacy OSSRH. |
The artifact name is the project name. A project called mylib
publishes as <groupId>:mylib:<version>. There is no name field ,
rename the project in bleep.yaml if you want a different artifact id.
Versions come from git tags via dynver.
A clean tag like v1.2.3 produces version 1.2.3. Any commit after
the tag, or a dirty working tree, produces a -SNAPSHOT suffix. There
is no version: field on the project for publishing.
Step 3: Set credentials in your environment
export SONATYPE_USERNAME=your-token-username
export SONATYPE_PASSWORD=your-token-password
export PGP_SECRET=base64-encoded-private-key
export PGP_PASSPHRASE=your-key-passphrase
For Sonatype Central, the username/password are user tokens generated at https://central.sonatype.com/account, not your account login.
To produce PGP_SECRET:
gpg --armor --export-secret-keys YOUR_KEY_ID | base64 | tr -d '\n'
(bleep publish setup does this for you.)
Step 4: Test the package locally
Before pushing to Central, publish to your local ivy cache:
bleep publish local-ivy
Inspect ~/.ivy2/local/<groupId>/<projectName>/, you should see the
JAR, sources JAR, javadoc JAR, and POM. Pull the artifact into another
project to verify it resolves cleanly.
Step 5: Publish to Maven Central
bleep publish sonatype
What happens:
- Bleep compiles every project that has
publish:configured. dynverinfers the version from git tags. With--assert-release, bleep refuses to proceed unless you're on a clean tag.- Each project is packaged into JAR + sources JAR + javadoc JAR + POM,
PGP-signed with
PGP_SECRET. - The bundle is uploaded to Sonatype Central, which closes and releases the staging repository on success.
Useful flags:
--version 1.2.3, override the dynver-inferred version.--assert-release, fail rather than publish a snapshot. Use this in CI release jobs.mylib, publish only the named project (and its publishable transitive deps).
Cross-published artifacts
A project with a cross: block publishes one Maven artifact per cross
variant. Scala cross variants get the standard Scala suffix
(mylib_2.13, mylib_3), Scala.js variants pick up _sjs1_3, and so
on, the convention matches what sbt produces, so consumers can depend
on mylib_3 from any tool. See
Cross-building for the workspace shape.
GitHub Actions release workflow
name: Release
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # dynver needs full history
- uses: bleep-build/bleep-setup-action@0.0.3
- name: Publish to Maven Central
env:
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
PGP_SECRET: ${{ secrets.PGP_SECRET }}
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
run: bleep publish --assert-release sonatype
fetch-depth: 0 is required so dynver can read the tag history.
Publishing to other repositories
Sonatype is the default for bleep publish sonatype, but bleep publish
also generates a subcommand for every named resolver in your
bleep.yaml. Declare the resolver:
resolvers:
- name: company-nexus
uri: https://nexus.company.com/repository/maven-releases/
Then:
bleep publish company-nexus
bleep publish setup configures auth for GitHub Packages, GitLab
Package Registry, and Google Artifact Registry interactively.
Troubleshooting
"No publishable projects found"
No project in your build has a publish: block. Add one to at least
one project.
"version would be a snapshot"
You ran bleep publish sonatype --assert-release on a commit that's
not at a clean tag. Either tag the commit (git tag v1.2.3), drop
--assert-release to publish a -SNAPSHOT, or pass --version 1.2.3
explicitly.
"Invalid signature" on Sonatype side
Your PGP_SECRET is wrong or your key isn't published to a key server.
Re-run bleep publish setup, the wizard publishes your key to the
default keyserver as part of setup.
"Repository not found" / staging close fails
Check that your Sonatype namespace (group ID) is verified and matches
the groupId in publish:. Sonatype's UI at
https://central.sonatype.com/publishing shows recent attempts and their
errors.
Next steps
- Cross-building: publish multiple Scala variants from one command.
- Private repositories: publish to your organization's internal Maven repo.
- CI/CD setup: full release pipeline.