feat(targets): add pkg-chocolatey target (Chocolatey Community Repository)#484
feat(targets): add pkg-chocolatey target (Chocolatey Community Repository)#484forgou37 wants to merge 5 commits into
Conversation
Greptile SummaryThis PR introduces the
Confidence Score: 2/5Not ready to merge — the generated nuspec will be malformed in common default-value scenarios, the zero-config installer path produces an unchecksum-able package, the portable type generates a PowerShell call that Chocolatey rejects, and the ship() method silently claims success without actually pushing anything. Several independent correctness issues affect the main output of the adapter. The double-escaping bug in renderNuspec means that any user relying on the owners-from-authors or summary-from-description defaults (with XML-special characters) will produce a nuspec that fails Chocolatey validation. The empty-checksum default path, the invalid portable script, and the false-success ship() return are each independently blocking for real usage. packages/targets/pkg-chocolatey/src/index.ts requires the most attention — specifically the escaping logic in renderNuspec, the default installer entry in renderInstallScript, the portable branch handling, and the ship() return path. Important Files Changed
Reviews (1): Last reviewed commit: "feat(targets): add pkg-chocolatey tests" | Re-trigger Greptile |
| const authors = escapeXml(config.authors ?? title); | ||
| const owners = escapeXml(config.owners ?? authors); | ||
| const homepage = escapeXml(config.homepage ?? 'https://sh1pt.com'); | ||
| const license = escapeXml(config.license ?? 'MIT'); | ||
| const description = escapeXml(config.description ?? `${title} package`); | ||
| const summary = escapeXml(config.summary ?? description); |
There was a problem hiding this comment.
Double XML-escaping on fallback defaults
authors and description are already XML-escaped at their assignment sites, but then passed as the fallback value into another escapeXml() call. Any user who sets authors (or description) with special characters like &, <, or > but omits owners (or summary) will end up with double-encoded output — e.g. &lt; instead of < — producing a malformed .nuspec that Chocolatey's validator will reject.
Fix: capture the raw config values first, then escape once at the point of interpolation, or store pre-escaped and pre-defaulted values without re-escaping.
| } | ||
|
|
||
| function renderInstallScript(config: Config, version: string): string { | ||
| const installers = config.installers ?? [{ url: defaultUrl(config, version, 'x64'), sha256: '', architecture: 'x64' as const }]; |
There was a problem hiding this comment.
Empty checksum in auto-generated installer entry
When config.installers is not provided, the auto-generated entry has sha256: ''. By default, Chocolatey enforces checksum validation and will immediately fail choco install with an error like "Checksum was empty" or "Checksum mismatch". This makes the zero-config path non-functional. At minimum, checksumType64 should be set to 'none' when the checksum is empty (though that disables security), or the caller should be required to supply installers.
| } else { | ||
| lines.push(` url64bit = '${primary.url}'`); | ||
| lines.push(` checksum64 = '${primary.sha256}'`); | ||
| lines.push(' checksumType64 = \'sha256\''); | ||
| lines.push(` fileType = \'${installerType}\'`); | ||
| lines.push(' silentArgs = "/S"'); | ||
| lines.push(' validExitCodes = @(0)'); | ||
| lines.push('}'); | ||
| lines.push(''); | ||
| lines.push('Install-ChocolateyPackage @packageArgs'); |
There was a problem hiding this comment.
portable type produces invalid Install-ChocolateyPackage call
When installerType is 'portable', the code falls into the else branch and emits fileType = 'portable' plus silentArgs = "/S", then calls Install-ChocolateyPackage. However, Install-ChocolateyPackage only accepts fileType values of exe or msi; passing 'portable' causes Chocolatey to throw immediately. Portable packages in Chocolatey do not download an installer at all — they typically copy a binary and call Install-BinFile (or rely on automatic shimming). A separate code path is needed for this case.
| async ship(ctx, config) { | ||
| const version = ctx.version.replace(/^v/, ''); | ||
| const packageId = config.packageId; | ||
|
|
||
| ctx.log(`push ${packageId} v${version} to Chocolatey Community Repository`); | ||
|
|
||
| if (ctx.dryRun) return { id: 'dry-run' }; | ||
|
|
||
| // TODO: pack the nupkg and push via `choco push` or the Chocolatey v2 API | ||
| // Requires CHOCOLATEY_API_KEY from ctx.secret('CHOCOLATEY_API_KEY') | ||
| return { | ||
| id: `${packageId}@${version}`, | ||
| url: `https://community.chocolatey.org/packages/${packageId}/${version}`, | ||
| }; |
There was a problem hiding this comment.
ship() returns a success result without performing any work
The non-dry-run path of ship() immediately returns { id, url } as if the package was pushed, but nothing is actually executed — no .nupkg is packed, no choco push is run, and CHOCOLATEY_API_KEY is never consumed. Callers (and users) will see a "success" with a valid-looking url while their package was never actually submitted. The TODO is acknowledged, but the early success return makes this a silent no-op rather than a clear failure or not-implemented signal.
| async status(id) { | ||
| const [name] = id.split('@'); | ||
| return { state: 'live', url: `https://community.chocolatey.org/packages/${name}` }; |
There was a problem hiding this comment.
status() always reports 'live' regardless of actual registry state
status() returns { state: 'live' } unconditionally without querying the Chocolatey API. Any package id — including one that was never published, was moderated-rejected, or was unlisted — will appear as live. If status is polled by CI to gate a deployment, this will always succeed falsely.
Closes #483
Adds the
pkg-chocolateytarget adapter for publishing packages to the Chocolatey Community Repository.What
.nuspecXML manifesttools/chocolateyInstall.ps1for zip/exe/msi/portable installer typesmanualSetupguide (API key from community.chocolatey.org)Related
Part of #133 — implements 4 main sh1pt CLI commands and their sub-commands.