feat: add PostgreSQL variant of build & test workflow
Separate file because Gitea can't make services: conditional. Service is reached by name on the job network; POSTGRES_* env is passed to the test step. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ca875ea6a4
commit
cdd0db3c65
2 files changed
+156
No files matched your search
@@ -0,0 +1,127 @@
|
||||
name: .NET Build & Test with PostgreSQL (Reusable)
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
solution:
|
||||
description: "Solution/project file to build (relative to working-directory). Empty = let dotnet pick the single sln/proj in working-directory"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
dotnet-version:
|
||||
description: ".NET SDK version"
|
||||
required: false
|
||||
default: "10.0.x"
|
||||
type: string
|
||||
configuration:
|
||||
description: "Build configuration"
|
||||
required: false
|
||||
default: "Release"
|
||||
type: string
|
||||
warnaserror:
|
||||
description: "Treat build warnings as errors"
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
working-directory:
|
||||
description: "Path where dotnet commands are executed (relative to repo root)"
|
||||
required: false
|
||||
default: "."
|
||||
type: string
|
||||
test-filter:
|
||||
description: "Optional dotnet test --filter expression"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
postgres-image:
|
||||
description: "PostgreSQL service image"
|
||||
required: false
|
||||
default: "postgres:17-alpine"
|
||||
type: string
|
||||
postgres-user:
|
||||
description: "PostgreSQL superuser (POSTGRES_USER of the service)"
|
||||
required: false
|
||||
default: "postgres"
|
||||
type: string
|
||||
postgres-password:
|
||||
description: "PostgreSQL password (throwaway CI database, not a secret)"
|
||||
required: false
|
||||
default: "postgres"
|
||||
type: string
|
||||
postgres-db:
|
||||
description: "Database created on service start (POSTGRES_DB). Empty = same as postgres-user"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
|
||||
DOTNET_NOLOGO: "1"
|
||||
SOLUTION: ${{ inputs.solution }}
|
||||
CONFIGURATION: ${{ inputs.configuration }}
|
||||
WARNASERROR: ${{ inputs.warnaserror }}
|
||||
TEST_FILTER: ${{ inputs.test-filter }}
|
||||
POSTGRES_HOST: postgres
|
||||
POSTGRES_PORT: "5432"
|
||||
POSTGRES_USER: ${{ inputs.postgres-user }}
|
||||
POSTGRES_PASSWORD: ${{ inputs.postgres-password }}
|
||||
POSTGRES_DB: ${{ inputs.postgres-db || inputs.postgres-user }}
|
||||
|
||||
# Reached by service name on the job network (container-mode runner).
|
||||
# No host port mapping, so concurrent jobs or a host PostgreSQL can't collide on 5432.
|
||||
services:
|
||||
postgres:
|
||||
image: ${{ inputs.postgres-image }}
|
||||
env:
|
||||
POSTGRES_USER: ${{ inputs.postgres-user }}
|
||||
POSTGRES_PASSWORD: ${{ inputs.postgres-password }}
|
||||
POSTGRES_DB: ${{ inputs.postgres-db || inputs.postgres-user }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{ inputs.dotnet-version }}
|
||||
|
||||
- name: Restore
|
||||
run: dotnet restore ${SOLUTION:+"$SOLUTION"}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
ARGS=(-c "$CONFIGURATION" --no-restore)
|
||||
if [ "$WARNASERROR" = "true" ]; then
|
||||
ARGS+=(-warnaserror)
|
||||
fi
|
||||
dotnet build ${SOLUTION:+"$SOLUTION"} "${ARGS[@]}"
|
||||
|
||||
# The image's init phase listens on the unix socket only, so an open TCP port means the final server is up.
|
||||
- name: Wait for PostgreSQL
|
||||
run: |
|
||||
for _ in $(seq 1 60); do
|
||||
if (exec 3<>"/dev/tcp/$POSTGRES_HOST/$POSTGRES_PORT") 2>/dev/null; then
|
||||
echo "PostgreSQL reachable at $POSTGRES_HOST:$POSTGRES_PORT"
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "::error::PostgreSQL not reachable at $POSTGRES_HOST:$POSTGRES_PORT after 60s"
|
||||
exit 1
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
ARGS=(-c "$CONFIGURATION" --no-build)
|
||||
if [ -n "$TEST_FILTER" ]; then
|
||||
ARGS+=(--filter "$TEST_FILTER")
|
||||
fi
|
||||
dotnet test ${SOLUTION:+"$SOLUTION"} "${ARGS[@]}"
|
||||
@@ -33,6 +33,35 @@ jobs:
|
||||
|
||||
No secrets.
|
||||
|
||||
## Variant with PostgreSQL
|
||||
|
||||
`dotnet-build-test-postgres.yaml` runs the same steps as above, plus a PostgreSQL service container for integration tests. It has its own file because Gitea can't make `services:` conditional.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build-test:
|
||||
uses: templates/dotnet-build-test/.gitea/workflows/dotnet-build-test-postgres.yaml@v1
|
||||
with:
|
||||
solution: MyApp.slnx
|
||||
postgres-user: myapp
|
||||
postgres-password: myapp
|
||||
# postgres-image: postgres:17-alpine
|
||||
# postgres-db: "" # empty = same as postgres-user
|
||||
```
|
||||
|
||||
It takes all inputs of `dotnet-build-test.yaml`, plus these:
|
||||
|
||||
| Name | Default | Description |
|
||||
|---|---|---|
|
||||
| `postgres-image` | `postgres:17-alpine` | Service image |
|
||||
| `postgres-user` | `postgres` | Superuser, so it can create and drop databases |
|
||||
| `postgres-password` | `postgres` | Throwaway CI password, not a secret |
|
||||
| `postgres-db` | `""` | Database created at start. Empty means the same as `postgres-user` |
|
||||
|
||||
The test step gets `POSTGRES_HOST=postgres`, `POSTGRES_PORT=5432`, `POSTGRES_USER`, `POSTGRES_PASSWORD` and `POSTGRES_DB` as environment variables. The job reaches the service by its name on the job network, which requires a container-mode runner. No host port is mapped. A step before the tests waits up to 60 s for the port to open.
|
||||
|
||||
No secrets.
|
||||
|
||||
## Versioning
|
||||
|
||||
Only major tags (`v1`, `v2`, …). Fixes and new optional inputs move the existing tag. Changing or removing inputs, or changing behavior, needs a new major tag.
|
||||
Reference in new issue
Block a user