Reusable CI/CD workflows for Forgejo. Other repos call these via uses: — no generator scripts, no copy-paste.
| Workflow | Description |
|---|---|
test-dotnet.yml |
.NET restore → build → test with auto-detection |
test-node.yml |
Node.js install → npm/yarn/pnpm test |
test-python.yml |
Python pip install → pytest |
test-e2e-dotnet-playwright.yml |
.NET E2E run inside mcr.microsoft.com/playwright/dotnet (browsers + system deps preinstalled, no host-side .NET install) |
build-images.yml |
Build and push Docker images |
scan-images.yml |
Build Docker images and run a Trivy vulnerability scan (CRITICAL by default) |
secret-scan.yml |
Scan repository contents for committed secrets via gitleaks |
schema-drift-graphql.yml |
Re-export GraphQL schema from a .NET backend, regenerate the typed frontend client, fail on drift |
deploy-kustomize.yml |
Deploy via kubectl + kustomize |
deploy-helm.yml |
Deploy via Helm upgrade --install |
Add a workflow file to your repo (e.g. .forgejo/workflows/ci.yml):
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
test:
uses: softwarehuset/templates/.forgejo/workflows/test-dotnet.yml@main
# That's it! Defaults handle the rest:
# - auto-detects *.sln / *.slnx
# - auto-detects and starts docker-compose if present
# - .NET 9.0, submodules enabled
# - test filter: Category!=Live&Category!=Integration
# Or with overrides:
test-custom:
uses: softwarehuset/templates/.forgejo/workflows/test-dotnet.yml@main
with:
dotnet-channel: "10.0"
solution-path: "src/MyApp.sln"
test-filter: ""jobs:
test:
uses: softwarehuset/templates/.forgejo/workflows/test-node.yml@main
# auto-detects package.json, lockfile → npm/yarn/pnpm
test-custom:
uses: softwarehuset/templates/.forgejo/workflows/test-node.yml@main
with:
node-version: "20"
working-directory: "frontend"jobs:
test:
uses: softwarehuset/templates/.forgejo/workflows/test-python.yml@main
# auto-detects pyproject.toml or setup.pyjobs:
build:
uses: softwarehuset/templates/.forgejo/workflows/build-images.yml@main
with:
images: |
Dockerfile|my-api|.
src/worker/Dockerfile|my-worker|src/workerjobs:
deploy:
needs: [build]
uses: softwarehuset/templates/.forgejo/workflows/deploy-kustomize.yml@main
with:
namespace: production
deployment: my-api
image: my-apijobs:
secret-scan:
runs-on: ubuntu-latest
uses: softwarehuset/templates/.forgejo/workflows/secret-scan.yml@main
# Defaults: gitleaks v8.21.2, .gitleaks.toml if present, scans the whole tree.jobs:
image-scan:
needs: [docker]
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
uses: softwarehuset/templates/.forgejo/workflows/scan-images.yml@main
with:
images: |
./backend/Dockerfile|my-api|.
./frontend/Dockerfile|my-frontend|./frontend
severity: "CRITICAL" # default
upload-sarif: true # default falseCatches FE/BE drift before merge: re-exports the schema from a .NET backend, regenerates the typed frontend client, and fails if either committed file is out of date. All installs are shell-based (no node24 third-party setup actions, which Forgejo Actions doesn't support yet).
jobs:
schema-drift:
needs: [test-backend]
runs-on: ubuntu-latest
uses: softwarehuset/templates/.forgejo/workflows/schema-drift-graphql.yml@main
with:
backend-project: backend/MyApp.Api/MyApp.Api.csproj
# frontend-dir: frontend (default)
# package-manager: bun (default; or npm/pnpm/yarn)
# schema-output: schema.graphql (default — diffed automatically)
# drift-paths: frontend/src/gql/ (default — additional paths to diff)jobs:
test-e2e:
needs: [docker]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
uses: softwarehuset/templates/.forgejo/workflows/test-e2e-dotnet-playwright.yml@main
with:
project-path: backend/MyApp.E2E.Tests/MyApp.E2E.Tests.csproj
backend-url: https://my-app.example.com
frontend-url: https://my-app.example.com
# retries: 1 (default — one retry, two attempts total)
# playwright-image: mcr.microsoft.com/playwright/dotnet:next-noble (default)
secrets: inheritThe job runs dotnet test inside mcr.microsoft.com/playwright/dotnet —
that image already contains the .NET SDK, the Playwright runtime, every
supported browser (Chromium, Firefox, WebKit), and their Linux system
dependencies. Nothing is installed on the runner.
Default tag is next-noble because every published vX.Y.Z-noble tag
through v1.59.0-noble is built on dotnet/sdk:8.0-noble, and most
softwarehuset E2E projects target net10.0. Override playwright-image
to pin to a specific tag once Playwright cuts a stable v1.60+-noble (which
will ship .NET 10 SDK).
jobs:
deploy:
uses: softwarehuset/templates/.forgejo/workflows/deploy-helm.yml@main
with:
helm_repo: https://charts.example.com
helm_repo_name: myrepo
chart: my-chart
release: my-release
namespace: production
version: "1.2.3"
values_file: k8s/values.yamlThese workflows are designed for bare-metal Ubuntu runners:
- No
container:orservices:(not supported) - Uses
wget(notcurl) for downloads - .NET installed via
dotnet-install.sh(notactions/setup-dotnet) - Docker compose v2 (
docker compose, notdocker-compose) - Secrets are inherited automatically (Forgejo doesn't support
secrets:inworkflow_call)
All workflows use smart auto-detection:
- Solution path: Finds
*.sln/*.slnxrecursively (up to 3 levels) - Docker compose: Finds and starts
docker-compose.yml/compose.ymlif present - Package manager: Detects
pnpm-lock.yaml/yarn.lock/package-lock.json - Python project: Detects
pyproject.toml/setup.py/requirements.txt
The samples/dotnet-api/ directory contains a sample .NET API with tests and docker-compose, used to validate the test-dotnet.yml workflow in this repo's own CI.