diff --git a/.forgejo/workflows/desktop.yml b/.forgejo/workflows/desktop.yml index 77bd7c2..76f01c9 100644 --- a/.forgejo/workflows/desktop.yml +++ b/.forgejo/workflows/desktop.yml @@ -154,20 +154,25 @@ jobs: run: bash desktop/packaging/arch/package-prebuilt.sh # Make the built .deb + .AppImage downloadable from the run (for hand-testing). - # continue-on-error: the Forgejo artifact backend may not be configured yet; a - # failed upload must not fail the build itself. - # Forgejo doesn't support the v4 artifact protocol (@actions/artifact v2+), - # so pin v3, which uses the older protocol the instance accepts. + # Mirrored action, never actions/upload-artifact: @v4+ throws + # GHESNotSupportedError on the hostname before it connects, and @v3 uploads + # something Gitea stores but will never serve back (it returns artifacts only + # through the v4 API, which filters on content_encoding='application/zip'). + # Pinned by SHA — the mirror auto-syncs, so a moved upstream tag would + # silently change what runs. See Scribe issues 2255 / 2270. + # No continue-on-error: a swallowed upload failure is exactly how 110 + # unreachable artifacts accumulated here unnoticed. Fail loudly instead. - name: Upload bundles - continue-on-error: true - uses: actions/upload-artifact@v3 + uses: https://git.fabledsword.com/bvandeusen/upload-artifact@cb8afe72b42edc798abfb8fcb556cf660d894245 with: name: thoughtsync-linux path: | desktop/src-tauri/target/release/bundle/appimage/*.AppImage desktop/src-tauri/target/release/bundle/deb/*.deb desktop/src-tauri/target/release/bundle/arch/*.pkg.tar.* - if-no-files-found: warn + # error, not warn: a build that bundles nothing should report as a + # failure, not as a green run with an empty artifact. + if-no-files-found: error # Tag builds only: publish a real, versioned Fabled-Git Release with the # AppImage + .deb attached — the stable fetch target the install script and @@ -262,13 +267,15 @@ jobs: --config "$updater" working-directory: desktop/src-tauri + # Mirrored action, never actions/upload-artifact — see the Linux job's + # Upload bundles step for the full reasoning. Pinned by SHA because the + # mirror auto-syncs. - name: Upload installer - continue-on-error: true - uses: actions/upload-artifact@v3 + uses: https://git.fabledsword.com/bvandeusen/upload-artifact@cb8afe72b42edc798abfb8fcb556cf660d894245 with: name: thoughtsync-windows path: desktop/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/*.exe - if-no-files-found: warn + if-no-files-found: error # Publishes to the SAME release as the Linux job. Safe to run twice: the # script reuses an existing release (409) and nullglob means each job uploads diff --git a/ci-requirements.md b/ci-requirements.md index 0489762..0165888 100644 --- a/ci-requirements.md +++ b/ci-requirements.md @@ -45,6 +45,33 @@ entirely on `ci-python:3.14`. (family rule 46). - The production runtime `Dockerfile` tracks python:3.12 so test results stay representative of the deployed image. +- **Artifacts — use the mirrored upload action, never `actions/upload-artifact`.** + ```yaml + uses: https://git.fabledsword.com/bvandeusen/upload-artifact@cb8afe72b42edc798abfb8fcb556cf660d894245 + ``` + Upstream's `actions/upload-artifact@v4` cannot work against this instance and + no server-side change will help: its `isGhes()` rejects any hostname that isn't + `github.com` / `*.ghe.com` / `*.localhost` and throws before it opens a + connection, so the server is never asked what it supports. `@v3` is worse — it + reports success, and Gitea then serves artifacts back only through the v4 API + (`content_encoding = application/zip`), so a v3 upload is stored but invisible + to every retrieval path. A green job producing nothing retrievable. + + `bvandeusen/upload-artifact` is our pull mirror of `forgejo/upload-artifact` + (the Forgejo project's fork, one commit on upstream v5.0.0 disabling that + check). Mirrored so CI depends on a commit we hold; pinned by SHA because the + mirror auto-syncs and a moved upstream tag would otherwise change what runs. + + Both desktop upload steps also set `if-no-files-found: error` and carry **no** + `continue-on-error`. They previously had both defaults inverted, which is how + 110 unreachable artifacts accumulated on this repo without anyone noticing — + the upload could fail or match nothing and the run still went green. Scribe + issues 2255 / 2270 have the full teardown. + + Download: `GET /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts` + for the id (global run id, not the repo-scoped run number), then + `…/actions/artifacts/{id}/zip`. Note the workstation has no `unzip` — use + `python3 -m zipfile -e`. ## Desktop (Tauri) lane — separate workflow