Compare commits
2 Commits
50beed4c02
..
v0.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 058280934b | |||
| 50006dd1a7 |
@@ -13,7 +13,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
IMAGE: gitea.larvit.se/${{ github.repository }}:${{ github.sha }}
|
IMAGE: gitea.larvit.se/${{ github.repository }}:${{ github.sha }}
|
||||||
REGISTRY_TOKEN: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
|
REGISTRY_TOKEN: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
|
||||||
REGISTRY_USER: ${{ secrets.DOCKER_REGISTRY_USER }}
|
REGISTRY_USER: ${{ vars.DOCKER_REGISTRY_USER }}
|
||||||
run: |
|
run: |
|
||||||
printf '%s' "$REGISTRY_TOKEN" | docker login gitea.larvit.se -u "$REGISTRY_USER" --password-stdin
|
printf '%s' "$REGISTRY_TOKEN" | docker login gitea.larvit.se -u "$REGISTRY_USER" --password-stdin
|
||||||
docker build -t "$IMAGE" .
|
docker build -t "$IMAGE" .
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ name: Mirror
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
tags: ['**']
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ['v[0-9]+.[0-9]+.[0-9]+']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
retag-image:
|
||||||
|
runs-on: docker-host
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4.2.2
|
||||||
|
- name: Promote the commit-hash image to semver + latest
|
||||||
|
env:
|
||||||
|
GIT_TAG: ${{ github.ref_name }}
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
|
||||||
|
REGISTRY_USER: ${{ vars.DOCKER_REGISTRY_USER }}
|
||||||
|
REPO: gitea.larvit.se/${{ github.repository }}
|
||||||
|
run: |
|
||||||
|
COMMIT=$(git rev-parse 'HEAD^{commit}')
|
||||||
|
VERSION=${GIT_TAG#v}
|
||||||
|
printf '%s' "$REGISTRY_TOKEN" | docker login gitea.larvit.se -u "$REGISTRY_USER" --password-stdin
|
||||||
|
docker pull "$REPO:$COMMIT" \
|
||||||
|
|| { echo "No image $REPO:$COMMIT - release tags must point at a commit whose branch passed the CI gate"; exit 1; }
|
||||||
|
for TAG in "$VERSION" "${VERSION%.*}" "${VERSION%%.*}" latest; do
|
||||||
|
docker tag "$REPO:$COMMIT" "$REPO:$TAG"
|
||||||
|
docker push "$REPO:$TAG"
|
||||||
|
done
|
||||||
|
- name: Log out of the registry
|
||||||
|
if: always()
|
||||||
|
run: docker logout gitea.larvit.se
|
||||||
@@ -1174,7 +1174,8 @@ Gitea Actions (`.gitea/workflows/`) runs the pipeline; the test job runs
|
|||||||
| Workflow | Trigger | Does |
|
| Workflow | Trigger | Does |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `ci.yml` | push, any branch except `main` | the full gate (`bash ci.sh`), then build + push the app image |
|
| `ci.yml` | push, any branch except `main` | the full gate (`bash ci.sh`), then build + push the app image |
|
||||||
| `mirror.yml` | push to `main`, or manual | force-push `main` + tags to the [GitHub mirror](https://github.com/larvit/plainpages) |
|
| `release.yml` | push of a `vX.Y.Z` tag | re-tag that commit's image as `X.Y.Z`, `X.Y`, `X`, `latest` |
|
||||||
|
| `mirror.yml` | push to `main` or any tag, or manual | force-push `main` + tags to the [GitHub mirror](https://github.com/larvit/plainpages) |
|
||||||
|
|
||||||
`main` is not re-tested on push — its commits are meant to arrive already green from a
|
`main` is not re-tested on push — its commits are meant to arrive already green from a
|
||||||
gated branch, so the status check to gate a merge on is `CI / full-gate (push)`.
|
gated branch, so the status check to gate a merge on is `CI / full-gate (push)`.
|
||||||
@@ -1191,15 +1192,22 @@ merges are fast-forward-only, the image for any `main` commit already exists —
|
|||||||
and pushed by that exact commit's branch gate; nothing is rebuilt after merge (build once,
|
and pushed by that exact commit's branch gate; nothing is rebuilt after merge (build once,
|
||||||
promote by re-tagging). One-time setup: on an account with package write in the `larvit` org,
|
promote by re-tagging). One-time setup: on an account with package write in the `larvit` org,
|
||||||
create a Gitea access token with `read:package` + `write:package`, and store the account name
|
create a Gitea access token with `read:package` + `write:package`, and store the account name
|
||||||
and token as the Actions secrets `DOCKER_REGISTRY_USER` and `DOCKER_REGISTRY_TOKEN`
|
as the Actions **variable** `DOCKER_REGISTRY_USER` and the token as the Actions **secret**
|
||||||
(a `GITEA_` prefix is rejected — reserved, like `GITHUB_`). Because this step runs
|
`DOCKER_REGISTRY_TOKEN` (a `GITEA_` prefix is rejected — reserved, like `GITHUB_`). Because
|
||||||
|
this step runs
|
||||||
inside the required gate, a missing/expired token (or registry outage) fails every branch's
|
inside the required gate, a missing/expired token (or registry outage) fails every branch's
|
||||||
gate and blocks **all** merges until restored — set the secrets before this lands, and use a
|
gate and blocks **all** merges until restored — set the secrets before this lands, and use a
|
||||||
non-expiring token or track its expiry. Retention: hash tags
|
non-expiring token or track its expiry. Retention: hash tags
|
||||||
accumulate one image per gated push, so an org-level package **cleanup rule**
|
accumulate one image per gated push, so an org-level package **cleanup rule**
|
||||||
(org Settings → Packages, applied by Gitea's daily cleanup cron) prunes them — type
|
(org Settings → Packages, applied by Gitea's daily cleanup cron) prunes them — type
|
||||||
`container`, remove versions matching `^[0-9a-f]{40}$` older than 30 days, keep the 10 most
|
`container`, remove versions matching `^[0-9a-f]{40}$` older than 30 days, keep the 10 most
|
||||||
recent and anything matching `^v?\d+\.\d+\.\d+$|^latest$` (semver tags are never pruned).
|
recent and anything matching `^\d+(\.\d+){0,2}$|^latest$` (release tags are never pruned).
|
||||||
|
|
||||||
|
**Releases** — pushing a semver git tag (`git tag v1.2.3 && git push origin v1.2.3`) runs
|
||||||
|
`release.yml`, which pulls that commit's hash image from the registry and re-tags it as
|
||||||
|
`1.2.3`, `1.2`, `1`, and `latest` — nothing is rebuilt, the released image is byte-identical
|
||||||
|
to the gated one. It fails loud if no hash image exists: release tags must point at a commit
|
||||||
|
that went through the gate (in practice, any `main` commit).
|
||||||
|
|
||||||
**GitHub mirror** — [github.com/larvit/plainpages](https://github.com/larvit/plainpages) is a
|
**GitHub mirror** — [github.com/larvit/plainpages](https://github.com/larvit/plainpages) is a
|
||||||
read-only mirror; after every merge, `mirror.yml` force-pushes `main` and all tags there,
|
read-only mirror; after every merge, `mirror.yml` force-pushes `main` and all tags there,
|
||||||
@@ -1215,8 +1223,9 @@ the first sync — until the secret exists, the mirror job fails loud on each me
|
|||||||
`docker-host` (config: `labels: ["docker-host:host"]`) on a machine with Docker Engine +
|
`docker-host` (config: `labels: ["docker-host:host"]`) on a machine with Docker Engine +
|
||||||
Compose, git, and Node + github.com access (for `actions/checkout`). Runs must **never
|
Compose, git, and Node + github.com access (for `actions/checkout`). Runs must **never
|
||||||
overlap** — the e2e stacks use fixed compose project names and the devstack suite uses host
|
overlap** — the e2e stacks use fixed compose project names and the devstack suite uses host
|
||||||
networking — so register exactly **one** `docker-host` runner, keep its capacity at 1, and
|
networking, and the workflows share the Docker daemon's registry login (`ci.yml` and
|
||||||
keep host ports 3000/4433 free.
|
`release.yml` each log in and log out) — so register exactly **one** `docker-host` runner,
|
||||||
|
keep its capacity at 1, and keep host ports 3000/4433 free.
|
||||||
|
|
||||||
## Production & deployment
|
## Production & deployment
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
- [x] CI/CD - Test on push to any branch except main. (`.gitea/workflows/ci.yml` runs `bash ci.sh`; the one-time act_runner setup it needs is documented in README → CI/CD.)
|
- [x] CI/CD - Test on push to any branch except main. (`.gitea/workflows/ci.yml` runs `bash ci.sh`; the one-time act_runner setup it needs is documented in README → CI/CD.)
|
||||||
- [x] CI/CD - Require PR to main and don't allow merge if tests does not pass. Only allow linear history and history that leaves the last commit hash on main the exact same as on the branch we just merged in. (Gitea branch protection on main + fast-forward-only merge style, set via API; documented in README → CI/CD.)
|
- [x] CI/CD - Require PR to main and don't allow merge if tests does not pass. Only allow linear history and history that leaves the last commit hash on main the exact same as on the branch we just merged in. (Gitea branch protection on main + fast-forward-only merge style, set via API; documented in README → CI/CD.)
|
||||||
- [x] CI/CD - Sync up to github after every successful merge to main, URL: git@github.com:larvit/plainpages.git - also note the true home top of the README. Force push to github, it should only ever be a mirror of the gitea.larvit.se repository. (`.gitea/workflows/mirror.yml` force-pushes main + tags over HTTPS with a dedicated account's PAT in the `MIRROR_GITHUB_TOKEN` secret; setup documented in README → CI/CD.)
|
- [x] CI/CD - Sync up to github after every successful merge to main, URL: git@github.com:larvit/plainpages.git - also note the true home top of the README. Force push to github, it should only ever be a mirror of the gitea.larvit.se repository. (`.gitea/workflows/mirror.yml` force-pushes main + tags over HTTPS with a dedicated account's PAT in the `MIRROR_GITHUB_TOKEN` secret; setup documented in README → CI/CD.)
|
||||||
- [x] CI/CD - Build docker images as part of the requirements to be able to merge to main. Push them with the git commit hash as docker tag. Push to container registry at Gitea. (`ci.yml` builds + pushes `gitea.larvit.se/larvit/plainpages:<commit hash>` after a green gate — with ff-only merges that is the main commit's image; auth via `DOCKER_REGISTRY_USER`/`DOCKER_REGISTRY_TOKEN` secrets, retention via an org cleanup rule; documented in README → CI/CD.)
|
- [x] CI/CD - Build docker images as part of the requirements to be able to merge to main. Push them with the git commit hash as docker tag. Push to container registry at Gitea. (`ci.yml` builds + pushes `gitea.larvit.se/larvit/plainpages:<commit hash>` after a green gate — with ff-only merges that is the main commit's image; auth via the `DOCKER_REGISTRY_USER` variable + `DOCKER_REGISTRY_TOKEN` secret, retention via an org cleanup rule; documented in README → CI/CD.)
|
||||||
- [ ] CI/CD - Re-tag docker images from git hash to semver when a semver git tag is pushed.
|
- [x] CI/CD - Re-tag docker images from git hash to semver when a semver git tag is pushed. (`release.yml` on a `vX.Y.Z` tag pulls the commit-hash image and re-tags it `X.Y.Z`/`X.Y`/`X`/`latest`, failing loud if the gated image is missing; tag pushes also trigger the GitHub mirror; documented in README → CI/CD.)
|
||||||
- [ ] CI/CD - Sync docker images to docker hub after each re-tag to git tags.
|
- [ ] CI/CD - Sync docker images to docker hub after each re-tag to git tags.
|
||||||
- [ ] CI/CD - Setup renovate bot.
|
- [ ] CI/CD - Setup renovate bot.
|
||||||
- [ ] Add an e2e test for the admin plugin's OAuth2-clients (Hydra) screen. The full-flow e2e suite runs without Hydra (compose.full.yml), so /admin/clients register/detail/delete is only unit-covered (src/http/app.test.ts); wire Hydra into an e2e stack and drive the screen in the browser.
|
- [ ] Add an e2e test for the admin plugin's OAuth2-clients (Hydra) screen. The full-flow e2e suite runs without Hydra (compose.full.yml), so /admin/clients register/detail/delete is only unit-covered (src/http/app.test.ts); wire Hydra into an e2e stack and drive the screen in the browser.
|
||||||
|
|||||||
Reference in New Issue
Block a user