[10.1] Continuous deployment to staging and production #35

Merged
dernbu merged 1 commit from feat/10.1-continuous-deployment into main 2026-06-14 04:49:46 +02:00
Owner

Add continuous deployment from Forgejo Actions using a self-hosted runner.

Changes

compose.yaml

  • Web port now uses ${WEB_HOST_PORT:?WEB_HOST_PORT is required}:${WEB_PORT:-3000}

Justfile

  • Added deploy target recipe supporting production/prod/main and staging/dev
  • Maps targets to env files, Compose project names, and host ports:
    • production → .env.production, lawnet_prod, port 3410
    • staging → .env.staging, lawnet_staging, port 3411
  • Deployment sequence: start postgres → run Flyway migrations → deploy services
  • Flyway failures are fatal to the workflow

.forgejo/workflows/deploy.yml (new)

  • Triggers on push to main (production) and dev (staging)
  • Runs on self-hosted runner with label lawnet-deploy
  • Renders target-specific env files from Forgejo secrets without logging values
  • Secret values passed via env: context to avoid YAML/shell escaping issues
  • Env files are deleted after deployment in an always() cleanup step

.forgejo/workflows/ci.yml

  • Updated compose config check to include WEB_HOST_PORT

.gitignore

  • Added .env.production and .env.staging

Required Forgejo secrets

  • PRODUCTION_POSTGRES_PASSWORD
  • PRODUCTION_INTERNAL_API_TOKEN
  • STAGING_POSTGRES_PASSWORD
  • STAGING_INTERNAL_API_TOKEN

Required runner setup

  • Self-hosted runner lawnet-deploy-01 with label lawnet-deploy
  • Docker Engine and Docker Compose plugin installed
  • Runner user can run Docker commands non-interactively

Closes #34

Add continuous deployment from Forgejo Actions using a self-hosted runner. ## Changes ### compose.yaml - Web port now uses `${WEB_HOST_PORT:?WEB_HOST_PORT is required}:${WEB_PORT:-3000}` ### Justfile - Added `deploy target` recipe supporting `production`/`prod`/`main` and `staging`/`dev` - Maps targets to env files, Compose project names, and host ports: - production → `.env.production`, `lawnet_prod`, port `3410` - staging → `.env.staging`, `lawnet_staging`, port `3411` - Deployment sequence: start postgres → run Flyway migrations → deploy services - Flyway failures are fatal to the workflow ### .forgejo/workflows/deploy.yml (new) - Triggers on push to `main` (production) and `dev` (staging) - Runs on self-hosted runner with label `lawnet-deploy` - Renders target-specific env files from Forgejo secrets without logging values - Secret values passed via `env:` context to avoid YAML/shell escaping issues - Env files are deleted after deployment in an `always()` cleanup step ### .forgejo/workflows/ci.yml - Updated compose config check to include `WEB_HOST_PORT` ### .gitignore - Added `.env.production` and `.env.staging` ## Required Forgejo secrets - `PRODUCTION_POSTGRES_PASSWORD` - `PRODUCTION_INTERNAL_API_TOKEN` - `STAGING_POSTGRES_PASSWORD` - `STAGING_INTERNAL_API_TOKEN` ## Required runner setup - Self-hosted runner `lawnet-deploy-01` with label `lawnet-deploy` - Docker Engine and Docker Compose plugin installed - Runner user can run Docker commands non-interactively Closes #34
feat: add continuous deployment workflow for staging and production
All checks were successful
CI / lint (pull_request) Successful in 1m6s
CI / typecheck (pull_request) Successful in 1m2s
CI / test (pull_request) Successful in 55s
CI / check-compose (pull_request) Successful in 4s
fda2a64b56
- Make web host port configurable via WEB_HOST_PORT env var
- Add deploy recipe to Justfile with production/staging targets
- Create Forgejo Actions deploy workflow triggered on push to main/dev
- Route main -> production (port 3410), dev -> staging (port 3411)
- Use separate Compose projects (lawnet_prod/lawnet_staging) for isolation
- Run Flyway migrations as explicit step before deploying services
- Render env files from Forgejo secrets in workflow, delete after deploy
- Add .env.production and .env.staging to .gitignore
- Fix CI check-compose to include WEB_HOST_PORT
dernbu force-pushed feat/10.1-continuous-deployment from fda2a64b56
All checks were successful
CI / lint (pull_request) Successful in 1m6s
CI / typecheck (pull_request) Successful in 1m2s
CI / test (pull_request) Successful in 55s
CI / check-compose (pull_request) Successful in 4s
to ebae747027
All checks were successful
CI / lint (pull_request) Successful in 59s
CI / typecheck (pull_request) Successful in 56s
CI / test (pull_request) Successful in 56s
CI / check-compose (pull_request) Successful in 4s
2026-06-14 04:33:43 +02:00
Compare
@ -0,0 +34,4 @@
WEB_PORT=3000
WEB_HOST_PORT=3410
INTERNAL_API_TOKEN=${INTERNAL_API_TOKEN}
ENVEOF
Author
Owner

The Postgres DB and user should be environment variables.

The Postgres DB and user should be environment variables.
dernbu marked this conversation as resolved
@ -0,0 +38,4 @@
chmod 600 .env.production
- name: Deploy
run: just deploy production
Author
Owner

Web port and host port are also environment variables. All variables in the environment file should be defined as environment variables, not hardcoded in the dependency. Then they are mirrored in the .env .example files.

Web port and host port are also environment variables. All variables in the environment file should be defined as environment variables, not hardcoded in the dependency. Then they are mirrored in the .env .example files.
dernbu marked this conversation as resolved
1 Outdated
@ -0,0 +1,151 @@
Author
Owner

Remove this file

Remove this file
dernbu marked this conversation as resolved
@ -0,0 +1,60 @@
## Parent
#10
Author
Owner

We moved this fileIt is a picture of.

We moved this fileIt is a picture of.
dernbu marked this conversation as resolved
dernbu force-pushed feat/10.1-continuous-deployment from ebae747027
All checks were successful
CI / lint (pull_request) Successful in 59s
CI / typecheck (pull_request) Successful in 56s
CI / test (pull_request) Successful in 56s
CI / check-compose (pull_request) Successful in 4s
to 9fa7ef4b75
All checks were successful
CI / lint (pull_request) Successful in 1m4s
CI / typecheck (pull_request) Successful in 59s
CI / test (pull_request) Successful in 56s
CI / check-compose (pull_request) Successful in 4s
2026-06-14 04:37:40 +02:00
Compare
.env.example Outdated
@ -5,4 +5,5 @@ POSTGRES_PASSWORD=lawnet_dev
DATABASE_URL=postgresql://lawnet:lawnet_dev@postgres:5432/lawnet
WEB_PORT=3000
WEB_HOST_PORT=3406
Author
Owner

Let's use a clear dummy variable, maybe a 5-digit port number, just to make sure it's clear.

Let's use a clear dummy variable, maybe a 5-digit port number, just to make sure it's clear.
dernbu marked this conversation as resolved
@ -89,3 +89,3 @@
steps:
- uses: actions/checkout@v4
- run: DATABASE_URL=postgresql://localhost:5432/db POSTGRES_DB=db docker compose config
- run: DATABASE_URL=postgresql://localhost:5432/db POSTGRES_DB=db WEB_HOST_PORT=3406 docker compose config
Author
Owner

Let's use a clear dummy variable, maybe a 5-digit port number, just to make sure it's clear.

Let's use a clear dummy variable, maybe a 5-digit port number, just to make sure it's clear.
dernbu marked this conversation as resolved
@ -0,0 +12,4 @@
runs-on: lawnet-deploy
environment:
name: production
env:
Author
Owner

We don't need this environment variable section anymore, do we?

We don't need this environment variable section anymore, do we?
dernbu marked this conversation as resolved
@ -0,0 +54,4 @@
runs-on: lawnet-deploy
environment:
name: staging
env:
Author
Owner

Same, you don't need this environment variable section in the Domino pose.

Same, you don't need this environment variable section in the Domino pose.
dernbu marked this conversation as resolved
Justfile Outdated
@ -49,0 +50,4 @@
# Deploy to a target environment.
# just deploy production (aliases: prod, main)
# just deploy staging (aliases: dev)
deploy target:
Author
Owner

We don't need to set the environment file and project variable rights because they're provided from the environment files, so we can remove this.

We don't need to set the environment file and project variable rights because they're provided from the environment files, so we can remove this.
dernbu marked this conversation as resolved
dernbu force-pushed feat/10.1-continuous-deployment from 9fa7ef4b75
All checks were successful
CI / lint (pull_request) Successful in 1m4s
CI / typecheck (pull_request) Successful in 59s
CI / test (pull_request) Successful in 56s
CI / check-compose (pull_request) Successful in 4s
to 969b11566e
Some checks failed
CI / lint (pull_request) Successful in 59s
CI / typecheck (pull_request) Successful in 1m1s
CI / test (pull_request) Successful in 55s
CI / check-compose (pull_request) Successful in 4s
Deploy / deploy-production (push) Has been cancelled
Deploy / deploy-staging (push) Has been cancelled
2026-06-14 04:42:34 +02:00
Compare
dernbu scheduled this pull request to auto merge when all checks succeed 2026-06-14 04:49:11 +02:00
dernbu merged commit 969b11566e into main 2026-06-14 04:49:46 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dernbu/lawnet-scraper!35
No description provided.