fix(ci): use nu http delete/put for generic-packages uploads (yotun pattern) #112

Merged
David merged 1 commit from fix/generic-packages-use-nu-http into main 2026-05-15 03:11:32 +02:00
Owner

Summary

Reverts #111's ^curl --user "$OWNER:$PAT" shape and switches to nushell's built-in http delete / http put with the Authorization: token ... bearer header, matching yotun/.forgejo/workflows/build-desktop-linux.yml. nu 0.112.2 (the version pinned in user CLAUDE.md) ships these out of the box; that path is what every other binary-publishing workflow in the org is converging on, so lets-chat should match. The bearer header IS the right form for this Forgejo's Generic Packages endpoint when sent via the nu http builtins - the earlier 401 from #110 was specific to ^curl's header handling in nu, not to the header content.

Changes (mirrored across all three files)

  • .forgejo/workflows/build-desktop-linux.yml
  • .forgejo/workflows/build-desktop-windows.yml
  • .forgejo/workflows/publish-release.yml

For each:

  • Drop both ^curl calls.
  • DELETE: http delete --full --allow-errors --headers $auth $url | get status with an explicit if $delete_status not-in [204 404] { exit 1 }. Previous "best-effort silent DELETE" swallowed real-error statuses (5xx, 403, etc.) without anyone noticing.
  • PUT: http put --content-type application/octet-stream --headers $auth $url (open --raw $src). Failure throws a nu error so the step exits non-zero automatically; no --fail-with-body scaffolding needed.
  • Auth: let auth = [Authorization $"token ($env.FORGEJO_TOKEN)"]. Revert of the --user/Basic-auth pattern across all three files.
  • URL building: url parse | update path ([...] | str join "/") | url join instead of dense $"..." interpolation. Lets url join handle encoding and keeps path segments listed vertically for review.

The job env (FORGEJO_TOKEN, PACKAGE_OWNER, PACKAGE_NAME) and the publish-release.yml upload table (linux binary, windows binary, manifest under ${version}/ + latest/latest.json) are unchanged.

Audit

grep -rn '\^curl\|--user\|Authorization' .forgejo/workflows/ after the change:

  • Zero ^curl references.
  • Zero --user flags.
  • The only --username/--password left is the ^docker login in build-oci-image.yml, which is a separate endpoint and has been passing.

Test plan

  • Next main push: build-desktop-linux.yml and build-desktop-windows.yml complete and land ${ORG}/generic/lets-chat/latest/lets-chat-desktop-{linux,windows}-x86_64[.exe] in the Generic Packages UI (no 401).
  • DELETE step prints 204 first run, 204 on re-runs.
  • curl -L "${SERVER}/api/packages/${ORG}/generic/lets-chat/latest/lets-chat-desktop-linux-x86_64" -o /tmp/lcd && file /tmp/lcd shows an ELF binary.
  • Future v* tag push: publish-release.yml succeeds end-to-end including latest/latest.json.
## Summary Reverts #111's `^curl --user "$OWNER:$PAT"` shape and switches to nushell's built-in `http delete` / `http put` with the `Authorization: token ...` bearer header, matching `yotun/.forgejo/workflows/build-desktop-linux.yml`. nu 0.112.2 (the version pinned in user CLAUDE.md) ships these out of the box; that path is what every other binary-publishing workflow in the org is converging on, so lets-chat should match. The bearer header IS the right form for this Forgejo's Generic Packages endpoint when sent via the nu http builtins - the earlier 401 from #110 was specific to `^curl`'s header handling in nu, not to the header content. ## Changes (mirrored across all three files) - `.forgejo/workflows/build-desktop-linux.yml` - `.forgejo/workflows/build-desktop-windows.yml` - `.forgejo/workflows/publish-release.yml` For each: - Drop both `^curl` calls. - DELETE: `http delete --full --allow-errors --headers $auth $url | get status` with an explicit `if $delete_status not-in [204 404] { exit 1 }`. Previous "best-effort silent DELETE" swallowed real-error statuses (5xx, 403, etc.) without anyone noticing. - PUT: `http put --content-type application/octet-stream --headers $auth $url (open --raw $src)`. Failure throws a nu error so the step exits non-zero automatically; no `--fail-with-body` scaffolding needed. - Auth: `let auth = [Authorization $"token ($env.FORGEJO_TOKEN)"]`. Revert of the `--user`/Basic-auth pattern across all three files. - URL building: `url parse | update path ([...] | str join "/") | url join` instead of dense `$"..."` interpolation. Lets `url join` handle encoding and keeps path segments listed vertically for review. The job env (`FORGEJO_TOKEN`, `PACKAGE_OWNER`, `PACKAGE_NAME`) and the `publish-release.yml` upload table (linux binary, windows binary, manifest under `${version}/` + `latest/latest.json`) are unchanged. ## Audit `grep -rn '\^curl\|--user\|Authorization' .forgejo/workflows/` after the change: - Zero `^curl` references. - Zero `--user` flags. - The only `--username/--password` left is the `^docker login` in `build-oci-image.yml`, which is a separate endpoint and has been passing. ## Test plan - [ ] Next `main` push: `build-desktop-linux.yml` and `build-desktop-windows.yml` complete and land `${ORG}/generic/lets-chat/latest/lets-chat-desktop-{linux,windows}-x86_64[.exe]` in the Generic Packages UI (no 401). - [ ] DELETE step prints `204` first run, `204` on re-runs. - [ ] `curl -L "${SERVER}/api/packages/${ORG}/generic/lets-chat/latest/lets-chat-desktop-linux-x86_64" -o /tmp/lcd && file /tmp/lcd` shows an ELF binary. - [ ] Future `v*` tag push: `publish-release.yml` succeeds end-to-end including `latest/latest.json`.
fix(ci): use nu http delete/put for generic-packages uploads (yotun pattern)
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 1m6s
76cb3fc664
#111's `^curl --user "$OWNER:$PAT"` form authenticated against the Forgejo Packages endpoint, but the right reference for this org turned out to be `yotun/.forgejo/workflows/build-desktop-linux.yml`, which uses nushell's built-in `http delete` / `http put` with the bearer header. nu 0.112.2 (the version pinned in user CLAUDE.md) ships these out of the box; that path is what every other binary-publishing workflow in the org is converging on, so lets-chat should match.

Mechanical port to the yotun shape across the three workflows that upload to the Generic Packages API:

- `.forgejo/workflows/build-desktop-linux.yml`
- `.forgejo/workflows/build-desktop-windows.yml`
- `.forgejo/workflows/publish-release.yml`

In each file:

- Drop both `^curl` calls. Replace the DELETE with `http delete --full --allow-errors --headers $auth $url` and explicitly check the response status: 204 means deleted, 404 means nothing was there, any other status `exit 1`s with the unexpected code. The previous "best-effort silent DELETE" pattern silently swallowed real-error statuses (5xx, 403, etc.).
- Replace the PUT with `http put --content-type application/octet-stream --headers $auth $url (open --raw $src)`. Failure throws a nu error so the step exits non-zero automatically; no `--fail-with-body` plumbing.
- Auth shape: `let auth = [Authorization $"token ($env.FORGEJO_TOKEN)"]`. The bearer header IS the right form for this Forgejo's Generic Packages endpoint when sent via `http put` / `http delete` - the earlier 401 was specific to `^curl`'s header handling in nu, not to the header content. Revert of the `--user`/Basic-auth pattern from #111 across all three files.
- URL building: `url parse | update path ([...] | str join "/") | url join` instead of `$"($env.GITHUB_SERVER_URL)/api/packages/..."` interpolation. Lets `url join` handle scheme/host/encoding details and keeps the path segments listed vertically.

The job env stays as-is (`FORGEJO_TOKEN`, `PACKAGE_OWNER`, `PACKAGE_NAME` pulled from the org variables / secrets configured by #107 and #110). `publish-release.yml`'s upload table is unchanged in content: same three entries (linux binary, windows binary, manifest), still under `${version}/...` and `latest/latest.json`.

Audit: `grep -rn '\^curl\|http put\|http delete\|--user\|Authorization' .forgejo/workflows/` after the change shows zero `^curl` references and zero `--user` flags across all workflows; the only `^docker login --username/--password` left is the container-registry login in `build-oci-image.yml`, which is a separate endpoint and has been passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
David merged commit 99352b4b14 into main 2026-05-15 03:11:32 +02:00
David deleted branch fix/generic-packages-use-nu-http 2026-05-15 03:11:32 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!112
No description provided.