The Forgejo Actions cache server at 172.18.0.27:41161 isn't reachable
from the test-web runner container; setup-node sat there waiting for
ETIMEDOUT each run. Drop `cache: 'npm'` so the step finishes in seconds.
`npm ci` still works deterministically from package-lock.json — net cost
is ~10-30s of registry fetch vs. 4m41s of timeout. Restore the cache
option once the runner-host network reaches the cache server (separate
operator task).
Operator wants CI to run on dev pushes (not just PR-to-main) but
path-scoped so Go-only diffs don't run web tests and vice versa. The
old test.yml ran everything on PR-to-main only; the new shape is two
focused workflows that each path-filter their own scope.
- test-web.yml — paths: web/**. Runs npm ci + npm run check + vitest.
Drops the npm run build step (vitest doesn't need the bundle; the
go:embed placeholder lives in web/build/index.html and never needs
the test job to rebuild it).
- test-go.yml — paths: **/*.go, go.mod, go.sum, sqlc.yaml, internal/**,
cmd/**. Runs go vet + golangci-lint + go test -short -race.
Both trigger on push to dev/main and PR to main. Tag pushes are not
covered — release.yml owns the tag-build path and tests have already
passed by the time a tag lands.
Drops the gomod-detect guard from test.yml — go.mod has been present
since M1 and is required for any Go file to exist anyway.
The flutter-ci runner image (CI-Runner/CI-flutter/Dockerfile) bakes in
Flutter 3.41.8 + Android cmdline-tools + platform-34 + build-tools
34.0.0 + JDK 17, so the workflow no longer needs subosito/flutter-action
to install everything per-job. Drops the setup step and switches
runs-on from the general-purpose go-ci to flutter-ci.
Per project memory feedback_dedicated_runner_labels.md: prefer
purpose-built labels with toolchains pre-installed over generic-runner +
setup-action ceremony on this self-hosted Forgejo deployment.
ubuntu-latest isn't a label any runner in this Forgejo deployment
advertises. The existing test.yml + release.yml both target the
project's go-ci label; flutter.yml should match. subosito/flutter-action@v2
installs the Flutter SDK on whatever runner picks up the job, so
go-ci is fine even though it isn't Flutter-pre-installed.
Triggers on push to dev/main, tag pushes, PR to main, and manual
dispatch — all path-filtered to flutter_client/** and the three
shared web inputs the sync_shared.sh script reads.
Steps:
- Sync tokens/error-copy/svg from web/ via tool/sync_shared.sh
- Re-run dart run tool/gen_tokens.dart and fail if lib/theme/tokens.dart
drifts from shared/fabledsword.tokens.json (catches forgotten regen
on the JSON edit path)
- flutter pub get / analyze --fatal-infos / test
- Debug APK on every push (uploaded as a workflow artifact)
- Release APK on tag, attached to the corresponding Forgejo release
via RELEASE_TOKEN (release.yml creates the release entry; this
workflow just attaches the APK as minstrel-<tag>.apk)
Uses subosito/flutter-action@v2 on ubuntu-latest for portability —
no dependence on a Flutter-pre-installed runner.
The repo now contains the Flutter mobile client at flutter_client/
(M7 #356). Two cleanups so the existing build pipelines don't churn
on Flutter-only changes:
1. .dockerignore — keep the Flutter project (and docs/, IDE noise,
git metadata) out of the Docker build context. The runtime image
was already unaffected (multi-stage drops everything but the Go
binary), but the COPY . . layer cache invalidated on every
Flutter edit. Build context shrinks ~2.4 MB and Flutter-only
pushes no longer force Go rebuilds.
2. test.yml + release.yml — paths-ignore on flutter_client/**,
docs/**, and **/*.md. Go/web tests + container build now skip
when the diff doesn't touch them. Tag releases still build broadly
since server + Flutter ship paired.
The Flutter-side workflow lands in M7 Task 21 with its own paths
filter restricting it to flutter_client/** and the shared web/
inputs (tokens.json, error-copy.json, album-fallback.svg).
Forgejo Actions fired both `push` and `pull_request` events for the same
commit when pushing to dev with an open PR — doubled CI runs on every PR
commit (e.g. #182 and #183 on PR #24's HEAD `95d68e3`). Drop the push
trigger entirely; PRs against main are the only quality gate that
matters in this workflow (dev → PR → main, never direct push to main).
Trade-off: direct pushes to dev with no open PR no longer get CI on
their own. Acceptable — the moment the PR opens, the pull_request event
fires and runs the same workflow.
Go's //go:embed needs web/build/ to exist at compile time. CI now
runs 'npm ci && npm run build && npm test' ahead of the Go steps
so the embed directive sees real, freshly-built assets.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The default GITHUB_TOKEN provided by Forgejo Actions lacks write:package
scope, so docker buildx push failed with 401 reqPackageAccess. Swap in
the repo-level REGISTRY_TOKEN secret (a PAT scoped write:package) for
docker login; github.actor still supplies the username.
Also drops the transient Docker environment diagnostics step — the
registry was the issue, the socket/buildx setup is fine.
Adds a manual-trigger hook so we don't need a fresh commit to re-run
this pipeline, and dumps docker/buildx state before the build so CI
failures are diagnosable without docker.sock guesswork.