diff --git a/.forgejo/workflows/android.yml b/.gitea/workflows/android.yml similarity index 93% rename from .forgejo/workflows/android.yml rename to .gitea/workflows/android.yml index cf8e28df..94fda31a 100644 --- a/.forgejo/workflows/android.yml +++ b/.gitea/workflows/android.yml @@ -11,7 +11,7 @@ on: tags: ['v*'] paths: - 'android/**' - - '.forgejo/workflows/android.yml' + - '.gitea/workflows/android.yml' pull_request: branches: [main] paths: @@ -96,9 +96,12 @@ jobs: working-directory: android env: - ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }} + # PKCS12 keystores collapse store + key password into a single + # value, so both env vars map to one secret. build.gradle still + # reads them separately to stay format-agnostic. + ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} - ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} steps: - name: Checkout diff --git a/.forgejo/workflows/flutter.yml b/.gitea/workflows/flutter.yml similarity index 93% rename from .forgejo/workflows/flutter.yml rename to .gitea/workflows/flutter.yml index 9cd0db45..1f678174 100644 --- a/.forgejo/workflows/flutter.yml +++ b/.gitea/workflows/flutter.yml @@ -18,7 +18,7 @@ on: - 'web/src/lib/styles/tokens.json' - 'web/src/lib/styles/error-copy.json' - 'web/static/placeholders/album-fallback.svg' - - '.forgejo/workflows/flutter.yml' + - '.gitea/workflows/flutter.yml' pull_request: branches: [main] paths: @@ -26,7 +26,7 @@ on: - 'web/src/lib/styles/tokens.json' - 'web/src/lib/styles/error-copy.json' - 'web/static/placeholders/album-fallback.svg' - - '.forgejo/workflows/flutter.yml' + - '.gitea/workflows/flutter.yml' workflow_dispatch: jobs: @@ -113,9 +113,12 @@ jobs: # the operator's persistent keystore. shell: bash env: - ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }} + # PKCS12 keystores collapse store + key password into a single + # value, so both env vars map to one secret. build.gradle still + # reads them separately to stay format-agnostic. + ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} - ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} run: | TAG="${GITHUB_REF#refs/tags/v}" flutter build apk --release --build-name="${TAG}" diff --git a/.forgejo/workflows/release.yml b/.gitea/workflows/release.yml similarity index 98% rename from .forgejo/workflows/release.yml rename to .gitea/workflows/release.yml index c2343ea3..93915ec0 100644 --- a/.forgejo/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,6 +1,6 @@ name: release -# Builds and pushes the minstrel container image to the Forgejo registry. +# Builds and pushes the minstrel container image to the Gitea registry. # # push to main → :main # push tag vX.Y.Z → :vX.Y.Z and :latest diff --git a/.forgejo/workflows/test-go.yml b/.gitea/workflows/test-go.yml similarity index 98% rename from .forgejo/workflows/test-go.yml rename to .gitea/workflows/test-go.yml index fc967f7e..9b7a0f55 100644 --- a/.forgejo/workflows/test-go.yml +++ b/.gitea/workflows/test-go.yml @@ -30,7 +30,7 @@ on: - 'internal/**' - 'cmd/**' - '.golangci.yml' - - '.forgejo/workflows/test-go.yml' + - '.gitea/workflows/test-go.yml' pull_request: branches: [main] paths: @@ -41,7 +41,7 @@ on: - 'internal/**' - 'cmd/**' - '.golangci.yml' - - '.forgejo/workflows/test-go.yml' + - '.gitea/workflows/test-go.yml' jobs: test: diff --git a/.forgejo/workflows/test-web.yml b/.gitea/workflows/test-web.yml similarity index 89% rename from .forgejo/workflows/test-web.yml rename to .gitea/workflows/test-web.yml index 6a156964..1cf5d5d7 100644 --- a/.forgejo/workflows/test-web.yml +++ b/.gitea/workflows/test-web.yml @@ -9,12 +9,12 @@ on: branches: [dev, main] paths: - 'web/**' - - '.forgejo/workflows/test-web.yml' + - '.gitea/workflows/test-web.yml' pull_request: branches: [main] paths: - 'web/**' - - '.forgejo/workflows/test-web.yml' + - '.gitea/workflows/test-web.yml' jobs: test: diff --git a/.gitignore b/.gitignore index f0261d93..61b3db32 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,11 @@ android/app/build/ android/local.properties android/*.iml android/app/*.iml +# Release signing material — keystore + extracted credentials live local +# only; the canonical copy is the Gitea repo secret (ANDROID_KEYSTORE_B64 +# + the alias/password secrets). Losing the local file is fine; losing +# the secret means rebuilding the keystore + reinstalling all clients. +android/*.keystore +android/*.keystore.* +android/*.jks +android/keystore.properties diff --git a/CLAUDE.md b/CLAUDE.md index 892e0558..52d895d9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,14 +44,15 @@ exists in Flutter: ## Repo conventions (already in force) -- **No GitHub — Forgejo only.** PR/issue ops via the forgejo MCP; CI runs under - `.forgejo/workflows/`. Never use `gh` or github.com URLs. +- **No GitHub — Gitea only.** PR/issue ops via the gitea MCP (server lives at + git.fabledsword.com, migrated from Forgejo); CI runs under `.gitea/workflows/`. + Never use `gh` or github.com URLs. - **Git flow:** work on `dev` → PR to protected `main` → tag release. Never push to `main`. - **No in-task tests/builds.** Do not run flutter/gradle/npm `test`/`build`/ `analyze` during implementation — CI verifies. Codegen scripts only. - **CI is operator-side.** After `git push origin dev`, the operator reports the - result; don't poll Forgejo. + result; don't poll Gitea. - **Specs/plans/audits/parity-map live local.** `docs/superpowers/` is `.gitignored` — save there for operator review; never commit those. - **detekt gates CI.** Watch the recurring ones: 60-line `LongMethod`, diff --git a/README.md b/README.md index 58265896..1a923024 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Two concurrent dev processes: truncates your dev `minstrel` data (admin user, library, likes). It brings up the compose Postgres and creates the test DB if missing. - CI runs both: a fast `go test -short -race` gate plus an integration - job with its own ephemeral Postgres (`.forgejo/workflows/test-go.yml`). + job with its own ephemeral Postgres (`.gitea/workflows/test-go.yml`). ### Production build @@ -101,7 +101,7 @@ Two concurrent dev processes: - Day-to-day work happens on `dev` (or feature branches merged into `dev`). - `main` is **protected** — changes land via PR from `dev`. -- Releases are cut by tagging `v*` off `main`; the release workflow builds and pushes the container image to the Forgejo registry. +- Releases are cut by tagging `v*` off `main`; the release workflow builds and pushes the container image to the Gitea registry. Task and milestone tracking: Fable (`Minstrel` project, id 12). diff --git a/ci-requirements.md b/ci-requirements.md index 06bcd7f4..05e9ebbc 100644 --- a/ci-requirements.md +++ b/ci-requirements.md @@ -12,8 +12,8 @@ git.fabledsword.com/bvandeusen/ci-go:1.26 git.fabledsword.com/bvandeusen/ci-flutter:3.44 ``` -- `ci-go:1.26` — Go server tests (`.forgejo/workflows/test-go.yml`), web SPA tests (`.forgejo/workflows/test-web.yml`), and the release container build (`.forgejo/workflows/release.yml`). -- `ci-flutter:3.44` — Flutter client tests + debug/release APK builds (`.forgejo/workflows/flutter.yml`). +- `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 @@ -42,6 +42,6 @@ None. - **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 Forgejo'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 Forgejo 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. +- **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. - **Friction asks.** None pending. The two images cover everything Minstrel needs. diff --git a/client/README.md b/client/README.md index 29e8de6c..b9ffaef4 100644 --- a/client/README.md +++ b/client/README.md @@ -8,7 +8,7 @@ in-app update flow (#397). CI populates this directory on tag releases: 1. `flutter.yml` builds `app-release.apk` and attaches it to the - Forgejo release as `minstrel-.apk`. + Gitea release as `minstrel-.apk`. 2. `release.yml` waits for that asset to appear, downloads it into this directory as `minstrel.apk`, writes the tag string to `minstrel.apk.version`, and `docker buildx build` includes both diff --git a/docker-compose.yml b/docker-compose.yml index 7e32270d..140294ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ version: "3.9" # tests at it: # make test-integration # (CI runs the same suite against its own ephemeral Postgres service — -# see .forgejo/workflows/test-go.yml.) +# see .gitea/workflows/test-go.yml.) # # Full stack (server + db): # docker compose up --build diff --git a/flutter_client/README.md b/flutter_client/README.md index b511e3ab..19c5e0d6 100644 --- a/flutter_client/README.md +++ b/flutter_client/README.md @@ -51,10 +51,10 @@ and re-run `./tool/sync_shared.sh`. ## CI -`.forgejo/workflows/flutter.yml` runs on push to dev/main, tag pushes, +`.gitea/workflows/flutter.yml` runs on push to dev/main, tag pushes, PR to main, and manual dispatch — path-filtered to `flutter_client/**` plus the shared web inputs. Steps: sync, analyze, test, build APK. -Debug APKs upload as artifacts; release APKs attach to the Forgejo +Debug APKs upload as artifacts; release APKs attach to the Gitea release on tag. ## Versioning @@ -67,7 +67,7 @@ when a server-side change requires a paired client update. ## Distribution -- **Android:** APK on the Forgejo release page. No Play Store for v1. +- **Android:** APK on the Gitea release page. No Play Store for v1. - **iOS:** TestFlight on tag (manual upload v1, automate later). ## Out-of-scope for slice 1