Skip to main content

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

GroupRequired (default)RollbackToken scope
Submitterfalsewarn-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 .nupkg to 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. Setting required: true therefore 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: true is 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                      # optional

Authentication

Anodizer needs a Chocolatey API key to push packages. You can provide it in two ways:

  1. Environment variable (recommended for CI): set CHOCOLATEY_API_KEY.
  2. Config field: set api_key in 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_moderation does 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 scraping community.chocolatey.org/packages/<name>.
  • skip_publish: true skips the entire publisher early — no nuspec is generated. Use disable: true if 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

FieldTypeDefaultDescription
namestringcrate nameOverride the Chocolatey package name
idsstring[]noneBuild ID filter: only include artifacts whose id is in this list
repository.ownerstringrequiredGitHub owner of the project repository
repository.namestringrequiredGitHub repository name
package_source_urlstringnoneURL shown as the package source in the Chocolatey gallery
ownersstringnoneChocolatey gallery package owner username
titlestringpackage nameDisplay title in the gallery (supports templates)
authorsstringcrate nameAuthor name(s) shown in the gallery
project_urlstringGitHub repo URLProject homepage URL
url_templatestringrelease URLCustom URL template for download URLs (overrides the release asset URL)
icon_urlstringnoneURL to the package icon image
copyrightstringnoneCopyright notice (supports templates)
descriptionstringCargo [package].descriptionPackage description (supports templates). Derived from Cargo.toml; falls back to crate name.
licensestringCargo [package].licenseSPDX 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_urlstringderivedExplicit <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_acceptanceboolfalseRequire users to accept the license before install
project_source_urlstringrepo URLSource code repository URL; defaults to the derived repository URL
docs_urlstringnoneDocumentation URL
bug_tracker_urlstring<repo>/issuesBug tracker URL; defaults to {repository}/issues
tagsstring or string[]package nameSpace-separated string or array of tags for the gallery
summarystringnoneShort summary of the package (supports templates)
release_notesstringnoneRelease notes for this version (supports templates)
dependenciesobject[]nonePackage dependencies (see below)
api_keystring$CHOCOLATEY_API_KEYChocolatey API key for choco push (supports templates)
source_repostringhttps://push.chocolatey.org/Push source URL
skip_publishboolfalseSkip pushing the .nupkg to the Chocolatey repository
disablebool or stringfalseDisable this publisher entirely. Accepts a bool or a template string that evaluates to a truthy value
usestringarchiveArtifact type to package, which also routes the install cmdlet: archiveInstall-ChocolateyZipPackage (unpacked into tools/); msiInstall-ChocolateyPackage -FileType 'msi' with -SilentArgs '/qn /norestart' and MSI -ValidExitCodes @(0, 1641, 3010); nsisInstall-ChocolateyPackage -FileType 'exe' with -SilentArgs '/S'.
amd64_variantstringv1amd64 microarchitecture variant filter (v1, v2, v3, v4)
republish_in_moderationbool or stringfalseRe-push the nupkg when a version is already in the community moderation queue. See Recovery flags.

Dependencies

Each entry in the dependencies array has:

FieldTypeDescription
idstringChocolatey package ID of the dependency
versionstringOptional version constraint (e.g., [1.0.0,))

How nuspec and nupkg files are generated

When the publish stage runs for Chocolatey, Anodizer:

  1. Finds Windows artifacts from the build stage, filtering by ids and amd64_variant if configured. It looks for both 32-bit (i686/i386/x86) and 64-bit artifacts.
  2. Generates a .nuspec XML manifest containing all package metadata (name, version, authors, description, license, tags, dependencies, etc.). All XML special characters are properly escaped.
  3. Generates a chocolateyInstall.ps1 PowerShell script placed in a tools/ directory, with SHA-256 checksums. The install cmdlet is routed by the artifact's installer type (the use: selector): an archive is unpacked via Install-ChocolateyZipPackage; an msi or nsis exe is run silently via Install-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.
  4. Runs choco pack to create the .nupkg file from the nuspec and tools directory.
  5. Runs choco push to upload the .nupkg to the configured source repository (defaults to https://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