Chocolatey
Publish to the Chocolatey Windows package manager
Anodizer generates Chocolatey .nuspec manifests and chocolateyInstall.ps1 PowerShell scripts, packs them into .nupkg files, and pushes them to the Chocolatey community repository (or a custom source). Chocolatey is the leading package manager for Windows, letting users install your tool with choco install myapp.
Classification
| Group | Required (default) | Rollback | Token scope |
|---|---|---|---|
| Submitter | false | warn-only (manual withdraw via community gallery) | n/a |
See Release resilience for the full classification table and the Submitter gate semantics.
The required: field
Default: false — a Chocolatey submission failure is logged but does not fail the release.
Set required: true to make the release exit non-zero if this publisher fails:
crates:
- name: myapp
publish:
chocolatey:
repository:
owner: myorg
name: myapp
license: MIT
required: true
Warning: Chocolatey is a submitter publisher — it pushes a
.nupkgto the community moderation queue; that queue resolves hours or days after the release completes. The publisher "succeeds" at queue-acceptance time, not at approval time. Settingrequired: truetherefore has no meaningful effect: the failure mode it guards against (queue rejection) happens asynchronously, long after the release exits.Anodizer emits this warning at config-validation time when
required: trueis set:<location>: publisher 'chocolatey' is a submitter (external moderation queue); `required: true` has no meaningful effect — the submitter gate evaluates at push time, not at approval time.See Publish overview — the
required:field for the full submitter-publisher semantics.
Minimal config
crates:
- name: myapp
publish:
chocolatey:
repository:
owner: myorg
name: myapp
license (and description / summary) derive from the crate's
Cargo.toml [package]. Chocolatey manifests require a license, so set
publish.chocolatey.license only to override the derived value, or if the
crate has no SPDX license.
Full config reference
crates:
- name: myapp
publish:
chocolatey:
name: myapp # optional; package name (default: crate name)
ids: [] # optional; build ID filter
repository:
owner: myorg # required
name: myapp # required
title: "My App" # optional; display title (template)
authors: "My Org" # optional
description: "A CLI tool" # optional (template)
summary: "A CLI tool" # optional (template)
license: MIT # optional; SPDX expression (MIT OR Apache-2.0)
license_url: "" # optional; defaults to derived GitHub LICENSE blob URL
require_license_acceptance: false # optional
project_url: "" # optional; defaults to GitHub repo URL
project_source_url: "" # optional; defaults to GitHub repo URL
icon_url: "" # optional; package icon URL
copyright: "" # optional (template)
docs_url: "" # optional
bug_tracker_url: "" # optional; defaults to <repo>/issues
package_source_url: "" # optional
owners: "" # optional; Chocolatey gallery owner
tags: [] # optional; array or space-separated string
release_notes: "" # optional (template)
url_template: "" # optional; override download URL
api_key: "{{ Env.CHOCOLATEY_API_KEY }}" # optional; defaults to env var
source_repo: "https://push.chocolatey.org/" # optional
skip_publish: false # optional; skip push without disabling
use: archive # optional; archive | msi | nsis
amd64_variant: v1 # optional; v1 | v2 | v3 | v4
republish_in_moderation: false # optional; re-push in-moderation copies
dependencies: # optional
- id: dotnet-runtime
version: "[6.0,)"
disable: false # optionalAuthentication
Anodizer needs a Chocolatey API key to push packages. You can provide it in two ways:
- Environment variable (recommended for CI): set
CHOCOLATEY_API_KEY. - Config field: set
api_keyin the chocolatey config. This field supports template rendering, so you can reference environment variables or other context values.
The environment variable is used as a fallback when api_key is not set in the config. To obtain an API key, sign in to chocolatey.org/account and generate one from your account page.
Common gotchas
- No Windows artifacts: if no Windows build artifacts exist, anodizer falls back to a placeholder GitHub release download URL and logs a warning. Ensure your build matrix includes at least one
*-pc-windows-*target. - Rejected versions: a version rejected by Chocolatey moderation cannot be replaced; the version must be bumped before re-pushing.
republish_in_moderationdoes not apply to rejected packages. - Moderation queue lag: the Chocolatey flat API (
/api/v2/Packages) only returns approved packages. Checking for an in-moderation version requires scrapingcommunity.chocolatey.org/packages/<name>. skip_publish: trueskips the entire publisher early — no nuspec is generated. Usedisable: trueif you want to disable without suppressing config validation.
Republish / update behavior
When republish_in_moderation: true, anodizer re-pushes a queued nupkg if the feed reports the version is in moderation. See Recovery flags: chocolatey.republish_in_moderation for the full mechanism.
Chocolatey config fields
| Field | Type | Default | Description |
|---|---|---|---|
name | string | crate name | Override the Chocolatey package name |
ids | string[] | none | Build ID filter: only include artifacts whose id is in this list |
repository.owner | string | required | GitHub owner of the project repository |
repository.name | string | required | GitHub repository name |
package_source_url | string | none | URL shown as the package source in the Chocolatey gallery |
owners | string | none | Chocolatey gallery package owner username |
title | string | package name | Display title in the gallery (supports templates) |
authors | string | crate name | Author name(s) shown in the gallery |
project_url | string | GitHub repo URL | Project homepage URL |
url_template | string | release URL | Custom URL template for download URLs (overrides the release asset URL) |
icon_url | string | none | URL to the package icon image |
copyright | string | none | Copyright notice (supports templates) |
description | string | Cargo [package].description | Package description (supports templates). Derived from Cargo.toml; falls back to crate name. |
license | string | Cargo [package].license | SPDX license expression (e.g. MIT, Apache-2.0, MIT OR Apache-2.0), emitted as the modern <license type="expression"> element. Derived from Cargo.toml; required by Chocolatey, so set this if the crate has none. |
license_url | string | derived | Explicit <licenseUrl>. When unset, anodizer derives a real GitHub …/blob/<tag>/LICENSE URL from repository; with no repository, no <licenseUrl> is emitted. anodizer never synthesizes an opensource.org/licenses/<spdx> URL — it 404s for compound SPDX and is rejected at moderation. |
require_license_acceptance | bool | false | Require users to accept the license before install |
project_source_url | string | repo URL | Source code repository URL; defaults to the derived repository URL |
docs_url | string | none | Documentation URL |
bug_tracker_url | string | <repo>/issues | Bug tracker URL; defaults to {repository}/issues |
tags | string or string[] | package name | Space-separated string or array of tags for the gallery |
summary | string | none | Short summary of the package (supports templates) |
release_notes | string | none | Release notes for this version (supports templates) |
dependencies | object[] | none | Package dependencies (see below) |
api_key | string | $CHOCOLATEY_API_KEY | Chocolatey API key for choco push (supports templates) |
source_repo | string | https://push.chocolatey.org/ | Push source URL |
skip_publish | bool | false | Skip pushing the .nupkg to the Chocolatey repository |
disable | bool or string | false | Disable this publisher entirely. Accepts a bool or a template string that evaluates to a truthy value |
use | string | archive | Artifact type to package, which also routes the install cmdlet: archive → Install-ChocolateyZipPackage (unpacked into tools/); msi → Install-ChocolateyPackage -FileType 'msi' with -SilentArgs '/qn /norestart' and MSI -ValidExitCodes @(0, 1641, 3010); nsis → Install-ChocolateyPackage -FileType 'exe' with -SilentArgs '/S'. |
amd64_variant | string | v1 | amd64 microarchitecture variant filter (v1, v2, v3, v4) |
republish_in_moderation | bool or string | false | Re-push the nupkg when a version is already in the community moderation queue. See Recovery flags. |
Dependencies
Each entry in the dependencies array has:
| Field | Type | Description |
|---|---|---|
id | string | Chocolatey package ID of the dependency |
version | string | Optional version constraint (e.g., [1.0.0,)) |
How nuspec and nupkg files are generated
When the publish stage runs for Chocolatey, Anodizer:
- Finds Windows artifacts from the build stage, filtering by
idsandamd64_variantif configured. It looks for both 32-bit (i686/i386/x86) and 64-bit artifacts. - Generates a
.nuspecXML manifest containing all package metadata (name, version, authors, description, license, tags, dependencies, etc.). All XML special characters are properly escaped. - Generates a
chocolateyInstall.ps1PowerShell script placed in atools/directory, with SHA-256 checksums. The install cmdlet is routed by the artifact's installer type (theuse:selector): an archive is unpacked viaInstall-ChocolateyZipPackage; an msi or nsis exe is run silently viaInstall-ChocolateyPackage(-FileType 'msi'/'exe'with the matching silent switches, plus MSI's reboot-aware-ValidExitCodes). If both 32-bit and 64-bit artifacts are found, a dual-architecture script is generated that passes both URLs; otherwise a single-architecture script is produced. - Runs
choco packto create the.nupkgfile from the nuspec and tools directory. - Runs
choco pushto upload the.nupkgto the configured source repository (defaults tohttps://push.chocolatey.org/).
If no Windows artifacts are found, Anodizer falls back to a placeholder GitHub release download URL and logs a warning.
skip_publish behavior
When skip_publish: true is set, Anodizer skips the entire publish function early -- no nuspec is generated, no choco pack is run, and no push occurs. This is useful when you want to define the Chocolatey config for future use without actually publishing, or when another system handles the push step.
In dry-run mode (--dry-run), Anodizer logs what it would do without generating any files or running any commands.
Full example
crates:
- name: myapp
publish:
chocolatey:
name: myapp
repository:
owner: myorg
name: myapp
title: "My App"
authors: "My Org"
description: "A fast CLI tool for doing things"
license: MIT
project_url: "https://github.com/myorg/myapp"
icon_url: "https://raw.githubusercontent.com/myorg/myapp/main/icon.png"
copyright: "Copyright 2026 My Org"
tags:
- cli
- tool
- devops
summary: "A fast CLI tool"
docs_url: "https://myorg.github.io/myapp"
bug_tracker_url: "https://github.com/myorg/myapp/issues"
project_source_url: "https://github.com/myorg/myapp"
dependencies:
- id: dotnet-runtime
version: "[6.0,)"
source_repo: "https://push.chocolatey.org/"
skip_publish: false