Wire the existing .gitea/workflows/deploy.yml job to publish the librenotes container image to a registry on every push to main and on tag v*, and switch the netcup deployment from build-on-host to pull-on-host. Currently the deploy job is gated on vars.DEPLOY_ENABLED == 'true' and skipped because no registry/secrets exist; netcup builds the image locally via compose.netcup.yaml (build: .).
Background
v0.1.0 is tagged but no image artifact exists.
Gitea's built-in container registry is available at git.librete.ch/v2/<owner>/<image> and authenticates with a personal/robot access token.
A registered netcup runner (label ubuntu-latest) already executes CI workflows.
Tasks
Create a Gitea robot account or scoped personal access token with package:write on public org
Set repo secrets:
REGISTRY=git.librete.ch
REGISTRY_USER=<robot-name>
REGISTRY_PASS=<token>
DEPLOY_HOST=root@netcup
DEPLOY_KEY=<deploy SSH private key> (issue/track via separate ops issue if needed)
DEPLOY_PATH=/srv/librenotes
HEALTH_URL=https://ln.cloud.librete.ch/healthz
Set repo variable DEPLOY_ENABLED=true
Replace compose.netcup.yamlbuild: . with image: ${LIBRENOTES_IMAGE} and resolve LIBRENOTES_IMAGE from .env on the host (e.g. git.librete.ch/public/librenotes:main)
Verify a main push triggers build → push → deploy → health check
Verify a v* tag push pins the immutable tag in LIBRENOTES_IMAGE on the host
Acceptance Criteria
git.librete.ch/public/librenotes:main and git.librete.ch/public/librenotes:v0.1.0 exist as packages
Deploy job runs and turns green on a main push
/srv/librenotes/ no longer needs a Go toolchain or build context (only compose.netcup.yaml + .env)
Rollback documented: edit LIBRENOTES_IMAGE to a prior tag and docker compose ... up -d
Dependencies
Depends on #30 (release pipeline foundation, closed)
## Summary
Wire the existing `.gitea/workflows/deploy.yml` job to publish the librenotes container image to a registry on every push to `main` and on tag `v*`, and switch the netcup deployment from build-on-host to pull-on-host. Currently the deploy job is gated on `vars.DEPLOY_ENABLED == 'true'` and skipped because no registry/secrets exist; netcup builds the image locally via `compose.netcup.yaml` (`build: .`).
## Background
- v0.1.0 is tagged but no image artifact exists.
- Gitea's built-in container registry is available at `git.librete.ch/v2/<owner>/<image>` and authenticates with a personal/robot access token.
- A registered netcup runner (label `ubuntu-latest`) already executes CI workflows.
## Tasks
- [ ] Create a Gitea robot account or scoped personal access token with `package:write` on `public` org
- [ ] Set repo secrets:
- `REGISTRY=git.librete.ch`
- `REGISTRY_USER=<robot-name>`
- `REGISTRY_PASS=<token>`
- `DEPLOY_HOST=root@netcup`
- `DEPLOY_KEY=<deploy SSH private key>` (issue/track via separate ops issue if needed)
- `DEPLOY_PATH=/srv/librenotes`
- `HEALTH_URL=https://ln.cloud.librete.ch/healthz`
- [ ] Set repo variable `DEPLOY_ENABLED=true`
- [ ] Replace `compose.netcup.yaml` `build: .` with `image: ${LIBRENOTES_IMAGE}` and resolve `LIBRENOTES_IMAGE` from `.env` on the host (e.g. `git.librete.ch/public/librenotes:main`)
- [ ] Verify a `main` push triggers build → push → deploy → health check
- [ ] Verify a `v*` tag push pins the immutable tag in `LIBRENOTES_IMAGE` on the host
## Acceptance Criteria
- [ ] `git.librete.ch/public/librenotes:main` and `git.librete.ch/public/librenotes:v0.1.0` exist as packages
- [ ] Deploy job runs and turns green on a `main` push
- [ ] `/srv/librenotes/` no longer needs a Go toolchain or build context (only `compose.netcup.yaml` + `.env`)
- [ ] Rollback documented: edit `LIBRENOTES_IMAGE` to a prior tag and `docker compose ... up -d`
## Dependencies
- Depends on #30 (release pipeline foundation, closed)
Follow-ups for tag-push pinning will land via #41 (backups) and #40 (SMTP) tracks; the build/push/deploy pipeline itself is complete.
All criteria met as of 2026-04-29T13:25:34Z:
- `git.librete.ch/public/librenotes:main` and `:sha-2c20edb` published as packages.
- Deploy job runs and turns green on a main push (run #30, success).
- /srv/librenotes/ uses pull-only flow: `compose.yaml` + `compose.netcup.yaml` + `.env` (LIBRENOTES_IMAGE=git.librete.ch/public/librenotes:main). No build context on the host.
- Rollback documented in docs/operations.md (perl edit of LIBRENOTES_IMAGE + compose pull && up -d).
- https://ln.cloud.librete.ch/healthz returns 200.
Follow-ups for tag-push pinning will land via #41 (backups) and #40 (SMTP) tracks; the build/push/deploy pipeline itself is complete.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Wire the existing
.gitea/workflows/deploy.ymljob to publish the librenotes container image to a registry on every push tomainand on tagv*, and switch the netcup deployment from build-on-host to pull-on-host. Currently the deploy job is gated onvars.DEPLOY_ENABLED == 'true'and skipped because no registry/secrets exist; netcup builds the image locally viacompose.netcup.yaml(build: .).Background
git.librete.ch/v2/<owner>/<image>and authenticates with a personal/robot access token.ubuntu-latest) already executes CI workflows.Tasks
package:writeonpublicorgREGISTRY=git.librete.chREGISTRY_USER=<robot-name>REGISTRY_PASS=<token>DEPLOY_HOST=root@netcupDEPLOY_KEY=<deploy SSH private key>(issue/track via separate ops issue if needed)DEPLOY_PATH=/srv/librenotesHEALTH_URL=https://ln.cloud.librete.ch/healthzDEPLOY_ENABLED=truecompose.netcup.yamlbuild: .withimage: ${LIBRENOTES_IMAGE}and resolveLIBRENOTES_IMAGEfrom.envon the host (e.g.git.librete.ch/public/librenotes:main)mainpush triggers build → push → deploy → health checkv*tag push pins the immutable tag inLIBRENOTES_IMAGEon the hostAcceptance Criteria
git.librete.ch/public/librenotes:mainandgit.librete.ch/public/librenotes:v0.1.0exist as packagesmainpush/srv/librenotes/no longer needs a Go toolchain or build context (onlycompose.netcup.yaml+.env)LIBRENOTES_IMAGEto a prior tag anddocker compose ... up -dDependencies
All criteria met as of 2026-04-29T13:25:34Z:
git.librete.ch/public/librenotes:mainand:sha-2c20edbpublished as packages.compose.yaml+compose.netcup.yaml+.env(LIBRENOTES_IMAGE=git.librete.ch/public/librenotes:main). No build context on the host.Follow-ups for tag-push pinning will land via #41 (backups) and #40 (SMTP) tracks; the build/push/deploy pipeline itself is complete.