android / Build + lint + test (push) Successful in 4m30s
android.yml and release.yml uploaded via actions/upload-artifact@v3, which
reports success while Gitea stores the result in a format its v4-only
artifact API will never serve back — 72 artifacts on this repo are on disk,
have valid DB rows, and are invisible to every retrieval path. Green jobs
producing nothing retrievable.
release.yml is a producer/consumer pair: android-release uploads
minstrel-apk and image-release downloads it to bundle into the container.
Swapping only the upload would have left download-artifact@v3 reading the
v1/v3 listing and finding nothing, so mirror the download side too —
bvandeusen/download-artifact, pull mirror of forgejo/download-artifact,
pinned at its v5 tag to match the upload pin's major.
Not actions/{upload,download}-artifact@v4: isGhes() throws on the hostname
before opening a connection, so no server-side change reaches it.
Upload steps also set if-no-files-found: error — image-release hard-depends
on minstrel-apk existing, so an empty upload must fail where it happens.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
80 lines
5.8 KiB
Markdown
80 lines
5.8 KiB
Markdown
# CI Requirements — Minstrel
|
|
|
|
> Copy of [the template](https://git.fabledsword.com/bvandeusen/CI-runner/src/branch/main/docs/requirements-sheet.template.md).
|
|
> Family-wide policy: `ci-runners.md` in the FabledRulebook.
|
|
|
|
## Runtime images
|
|
|
|
Minstrel's four workflows consume two CI images:
|
|
|
|
```
|
|
git.fabledsword.com/bvandeusen/ci-go:1.26
|
|
git.fabledsword.com/bvandeusen/ci-flutter:3.44
|
|
```
|
|
|
|
- `ci-go:1.26` — Go server tests (`.gitea/workflows/test-go.yml`), web SPA tests (`.gitea/workflows/test-web.yml`), and the release container build (`.gitea/workflows/release.yml`).
|
|
- `ci-flutter:3.44` — Flutter client tests + debug/release APK builds (`.gitea/workflows/flutter.yml`).
|
|
|
|
## Image deps used
|
|
|
|
### From `ci-go:1.26`
|
|
- **Go** (1.26 toolchain) — `go vet`, `go test -race`, `go build`, `go mod`.
|
|
- **Node + npm** — `npm ci` and `npm test` / `npm run check` in `test-web.yml`.
|
|
- **golangci-lint** — lint pass in `test-go.yml`.
|
|
- **docker CLI** — bridge-IP discovery of the per-job Postgres service container in `test-go.yml` integration job (via the runner's shared `/var/run/docker.sock`).
|
|
- **docker buildx** — release container build + push in `release.yml`.
|
|
- **curl** — release-asset polling / upload in `release.yml`.
|
|
|
|
### From `ci-flutter:3.44`
|
|
- **Flutter** (3.44 stable channel) — `flutter pub get`, `flutter analyze --fatal-infos`, `flutter test`, `flutter build apk` (debug + signed release).
|
|
- **Dart** — `dart run tool/gen_tokens.dart`, `dart run build_runner build` (drift codegen).
|
|
- **Android SDK + NDK + cmdline-tools + build-tools** — APK assembly + signing.
|
|
- **Java 25** — Gradle / Android build.
|
|
- **git** — `actions/checkout@v4` baseline (and any shell git operations).
|
|
- **base64 + curl** — keystore decode + release-asset upload in the tag-build path.
|
|
|
|
## Per-job tool installs
|
|
|
|
None.
|
|
|
|
## Notes
|
|
|
|
- **Label/image split.** Workflows keep `runs-on: go-ci` / `runs-on: flutter-ci` as the scheduling label per the [`ci-runners.md`](https://…/FabledRulebook/ci-runners.md) "label = scheduling handle, image = `container.image`" pattern. The labels are intentional handles, not toolchain assertions.
|
|
- **Integration-job docker-socket dependency.** `test-go.yml`'s integration job uses the runner's shared docker socket (`/var/run/docker.sock`) to bridge-IP-discover the per-job Postgres service container by name + network intersection — the dev compose's `minstrel-postgres-*` containers are explicitly skipped as belt-and-suspenders. Depends on `act_runner.valid_volumes` whitelisting the socket; if that ever stops auto-mounting, integration tests fail at the `docker inspect` step.
|
|
- **Go toolchain pin.** `go.mod` is on `go 1.25.0` because `golang.org/x/crypto v0.51.0` declares 1.25 as its minimum. `ci-go:1.26` satisfies this with headroom. Future `x/crypto` bumps that move the Go floor should be paired with an image-tag bump in this file + the workflows.
|
|
- **In-app update channel polling.** `release.yml` polls Gitea's release-asset API for up to 15 min on tag pushes to fetch the APK that `flutter.yml` is concurrently attaching to the same release. The asset eventually appears because `flutter.yml` and `release.yml` run in parallel on the same tag; if the polling times out, the server image ships without the bundled update channel (graceful degradation, not a build failure).
|
|
- **Cache server reachability.** `test-web.yml` does NOT use `cache: 'npm'` on `actions/setup-node` — the Gitea Actions cache server isn't reachable from this runner's container network and `setup-node` was burning ~4m41s on ETIMEDOUT before failing open. With the migration to `ci-go:1.26`, `setup-node` is removed entirely (Node is in the image). The cache concern reappears if a future change re-introduces a network-dependent action.
|
|
- **Artifacts — use the mirrored actions, never `actions/{upload,download}-artifact`.**
|
|
```yaml
|
|
uses: https://git.fabledsword.com/bvandeusen/upload-artifact@cb8afe72b42edc798abfb8fcb556cf660d894245
|
|
uses: https://git.fabledsword.com/bvandeusen/download-artifact@1314311ddb542af343a82d478ac786ceada4143a
|
|
```
|
|
Upstream's `@v4+` cannot work against this instance and no server-side change
|
|
will help: `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; that is how
|
|
72 unreachable artifacts accumulated on this repo. Scribe issues 2255 / 2270.
|
|
|
|
Both are pull mirrors of the Forgejo project's forks
|
|
(`code.forgejo.org/forgejo/{upload,download}-artifact`, one commit on upstream
|
|
disabling that check), mirrored so CI depends on commits we hold and pinned by
|
|
SHA because the mirrors auto-sync every 8h — a moved upstream tag would
|
|
otherwise silently change what runs. The pins are upstream's `v5` tags on both
|
|
sides; **keep the majors matched.** `release.yml` is a producer/consumer pair —
|
|
`android-release` uploads `minstrel-apk`, `image-release` downloads it — and
|
|
mixing protocol versions across that pair yields an empty listing rather than
|
|
an error, which is the failure mode this whole entry exists to prevent.
|
|
|
|
Upload steps set `if-no-files-found: error` rather than the default `warn`, so
|
|
an upload that matches nothing fails its own job instead of failing the
|
|
consumer later.
|
|
|
|
Retrieval: `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`. The workstation has no `unzip` — use
|
|
`python3 -m zipfile -e`.
|
|
- **Friction asks.** None pending. The two images cover everything Minstrel needs.
|