Skip to main content

Selecting publishers

Run a tailored subset of publishers with the --publishers allowlist and the unified --skip denylist

Anodizer runs every configured publisher by default. Two flags narrow that set when you want a targeted release — --publishers (an allowlist) and --skip (a denylist). Both are available on release, publish, continue, and check config, and both accept the same publisher vocabulary, so a selection that works on one command works on all of them. continue resumes a stalled release through the same publish pipeline, so it validates and honors the selectors identically — a typo there is rejected before any publisher runs, the same one-way-door guard the other commands carry.

Allowlist vs denylist

FlagRoleEffect when set
--publishers <a,b,…>allowlistOnly the named publishers run. Every other publisher — including the irreversible publish stages blob, snapcraft-publish, docker, docker-sign, and announce (the last broadcasts to webhooks/Slack/Twitter/Mastodon/Bluesky) — is deselected. (The release stage that creates the GitHub release is the substrate the others depend on and is governed by --skip=release only; see the valid-names note below.)
--skip <a,b,…>denylistThe named stages and publishers are removed; everything else runs.

Both flags are comma-separated and may be repeated:

anodizer release --publishers cargo,homebrew
anodizer release --publishers cargo --publishers homebrew   # equivalent
anodizer release --skip npm,dockerhub

Precedence: --skip always wins

When a publisher appears in both lists, --skip removes it. This makes the denylist a hard veto you can layer on top of an allowlist:

# Allow cargo + homebrew, but veto homebrew anyway → only cargo runs.
anodizer release --publishers cargo,homebrew --skip homebrew

Empty means "all configured"

Omitting both flags (or passing empty values) runs every configured publisher — the default release behavior is unchanged:

anodizer release           # every configured publisher runs

The valid publisher names

--publishers and --skip accept these publisher names (the canonical token for each publisher is its own name — anodizer derives the set from the publisher registry, so it never drifts):

Publisher nameAlso a stage name?
cargoyes
homebrewyes
scoopyes
nixyes
auryes
krewyes
wingetyes
chocolateyyes
github-releasethe stage token is release
npmpublisher only
dockerhubpublisher only
uploadspublisher only
artifactorypublisher only
cloudsmithpublisher only
gemfurypublisher only
schemastorepublisher only
mcppublisher only
upstream-aurpublisher only
blobthe publish stage blob (object-store upload)
snapcraft-publishthe publish stage snapcraft-publish (Snap Store upload)
dockerthe publish stage docker (image-registry push)
docker-signthe publish stage docker-sign (cosign signatures to the registry)
announcethe publish stage announce (irreversible external broadcasts — webhooks, Slack, Twitter, Mastodon, Bluesky)

A name in the yes rows resolves the same whether you reach it through --skip (which also accepts stage tokens) or --publishers. The publisher only names have no stage of their own, so before this selection surface the only way to gate them was per-block config — now they honor --skip/--publishers uniformly at dispatch time.

The last five names — blob, snapcraft-publish, docker, docker-sign, announce — are publish stages rather than dispatch publishers, but each performs an external, irreversible push (an object store, the Snap Store, an image registry, registry signatures, or — for announce — broadcasts to webhooks/Slack/Twitter/Mastodon/Bluesky). They are therefore governed by the same selectors: --publishers cargo deselects them, and --publishers blob allow-lists a blob-only upload. Like homebrew, announce depends on the release substrate (it reads the release URL) yet is itself a leaf, so the allowlist governs it just like the others. The one exception is the release stage that creates the GitHub/GitLab/Gitea release: it is the substrate every other publisher depends on (manifests reference its assets; announce needs the release URL), so it is governed by --skip=release only and is never dropped by a --publishers allowlist.

Canonical names: homebrew, not brew; chocolatey, not choco

The selection vocabulary uses each publisher's full name. The short forms are rejected with a loud error so a typo can never silently widen or narrow a release:

$ anodizer release --skip brew
Error: invalid --skip value(s): brew. Valid options: …, homebrew, …, chocolatey, …

$ anodizer release --publishers crates
Error: invalid --publishers value(s): crates. Valid publishers: cargo, …

Use homebrew, chocolatey, and cargo (the canonical names from the table above).

Worked examples

Publish a single channel from a finished build

anodizer publish reuses artifacts already in dist/ and runs only the publish pipeline. Pair it with --publishers to release one channel without re-running the rest:

$ anodizer publish --publishers npm
 publishing npm
 skipped cargo — not in --publishers allowlist
 skipped homebrew — not in --publishers allowlist

Exclude one publisher from a full release

$ anodizer release --skip npm
 skipped npm — excluded via --skip
    # every other configured publisher runs

Tailor a release to two publishers

$ anodizer release --publishers cargo,homebrew
 publishing cargo
 publishing homebrew
 skipped npm — not in --publishers allowlist
 skipped dockerhub — not in --publishers allowlist

Two deselect outputs: the dispatch line and the summary line

A deselected publisher is never silent. anodizer emits the deselect line at two points in the run — in-flight (as the publish pipeline reaches the publisher) and again in the publish summary — with the same distinguished wording at both. The two outputs differ only in phase, not in text: both come from the one deselected_reason source, so they always name the same cause.

Wording (both phases)When it applies
skipped <name> — excluded via --skipThe publisher was named in the --skip denylist.
skipped <name> — not in --publishers allowlistA non-empty --publishers allowlist was given and this publisher was not in it.

The line is distinguished: it names the exact cause so you can confirm a publisher was turned off the way you intended. When both selectors apply to one publisher, --skip wins and the line reports the denylist cause.

The five publish stages (blob, snapcraft-publish, docker, docker-sign, announce) run outside the dispatch loop, so a deselected one emits a single line at its stage — skipped blob — not in --publishers allowlist / skipped docker — excluded via --skip — rather than the in-flight-plus-summary pair. The wording is identical, so you still see exactly which selector turned it off.

$ anodizer release --skip npm
 skipped npm — excluded via --skip   # in-flight
    # every other configured publisher runs
 skipped npm — excluded via --skip   # summary (same wording)
$ anodizer release --publishers cargo
 publishing cargo
 skipped npm — not in --publishers allowlist   # in-flight

 skipped npm — not in --publishers allowlist   # summary (same wording)

Validating a selection ahead of release

check config --publishers <names> validates the selection against the configured publishers without running anything. Naming a publisher you forgot to configure is an error, so you catch a selection mistake before tag time rather than at release time:

$ anodizer check config --publishers cargo
 validating configuration
 Config is valid.

$ anodizer check config --publishers npm
Error: publisher 'npm' named in --publishers is not configured (no npm publish block)

The same loud error guards a typo here as on release/publish:

$ anodizer check config --publishers crates
Error: invalid --publishers value(s): crates. Valid publishers: cargo, …

Typos fail loud — one-way-door safety

Several publishers push to one-way-door registries (crates.io, Cloudsmith, Chocolatey, winget, AUR). A misread selection must never quietly publish nothing or everything, so anodizer rejects any unknown token with a nonzero exit before dispatch begins:

$ anodizer release --publishers homebrwe   # typo
Error: invalid --publishers value(s): homebrwe. Valid publishers: cargo, …
$ echo $?
1

Because the error fires before the publish pipeline runs, a typo can never reach a registry — you fix the name and re-run.

See also

  • required: — control which publisher failures fail the release.
  • NPM — npm provenance requires a GitHub-hosted runner, so CI peels npm onto a separate github-hosted job while the rest of the release runs elsewhere.