-
Notifications
You must be signed in to change notification settings - Fork 0
216 lines (199 loc) · 7.83 KB
/
Copy pathpython-react-ci.yml
File metadata and controls
216 lines (199 loc) · 7.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
name: Reusable Python+React CI
# Reusable CI workflow for homelabforge Python+React repos.
# Consumers wrap this via a thin .github/workflows/ci.yml that calls:
#
# jobs:
# ci:
# uses: homelabforge/shared-workflows/.github/workflows/python-react-ci.yml@v1.4.3
# with:
# enable-translations: true # mygarage only
# enable-bootstrap-token: true # vulnforge only
# security-tripwire-script: .github/scripts/security-tripwire.sh
#
# Inputs default to the homelab-standard values. Bun version comes from
# the consumer repo's .bun-version file (single source of truth).
#
# The backend/frontend/e2e/api-freshness matrix lives in the shared
# _python-react-tests.yml building block (called as the `tests` job
# below) so CI and publish stay in lockstep. CI-specific jobs
# (pg-migrations, docker-build-test) stay here.
on:
workflow_call:
inputs:
python-version:
type: string
default: "3.14"
bun-version-file:
type: string
default: ".bun-version"
bun-version:
# Escape hatch — leave empty to use bun-version-file.
type: string
default: ""
enable-e2e:
type: boolean
default: true
enable-translations:
type: boolean
default: false
enable-bootstrap-token:
type: boolean
default: false
enable-api-freshness-check:
type: boolean
default: true
enable-pg-migrations:
# Run the consumer's docker-compose.test.yml stack and execute
# pytest against its PostgreSQL sidecar. Off by default — only
# mygarage ships a compose stack today (added in v2.27.0-rc2).
# See pg-migrations-* inputs below for paths/service.
type: boolean
default: false
pg-migrations-compose-file:
type: string
default: "docker-compose.test.yml"
pg-migrations-service:
type: string
default: "mygarage-test"
pg-migrations-pytest-path:
type: string
default: "tests/migrations/"
runner-os:
type: string
default: ubuntu-latest
security-tripwire-script:
type: string
default: ""
permissions:
contents: read
jobs:
tests:
# backend + frontend + e2e + api-freshness, shared with publish.
# Must be a full owner/repo path pinned to this release's own tag: a `./`
# local path resolves against the CONSUMER repo (which has no such file)
# when this reusable workflow is called cross-repo, causing a 0s
# startup_failure. Bump the @ref on every release.
uses: homelabforge/shared-workflows/.github/workflows/_python-react-tests.yml@v1.4.3
with:
python-version: ${{ inputs.python-version }}
bun-version-file: ${{ inputs.bun-version-file }}
bun-version: ${{ inputs.bun-version }}
enable-e2e: ${{ inputs.enable-e2e }}
enable-translations: ${{ inputs.enable-translations }}
enable-bootstrap-token: ${{ inputs.enable-bootstrap-token }}
enable-api-freshness-check: ${{ inputs.enable-api-freshness-check }}
runner-os: ${{ inputs.runner-os }}
security-tripwire-script: ${{ inputs.security-tripwire-script }}
pg-migrations:
# Why this job exists:
# The repo's existing test-backend job runs pytest against
# SQLite. Migration 054 in mygarage v2.27.0-rc1 shipped with two
# PG-only bugs (DATETIME column type, ADD CONSTRAINT IF NOT
# EXISTS) that all CI passes ignored — `Base.metadata.create_all`
# was always run before the migrations, so by the time the
# migration's literal SQL ran the columns/constraints already
# existed and the idempotency guards short-circuited. The
# migration's actual SQL never executed against PG in any test.
#
# Consumers can opt in to a PG matrix via a docker-compose stack
# that pairs a postgres:16-alpine sidecar with a test image and
# a pre-migration SQL baseline. Migration tests load the
# baseline into a clean PG schema and exercise the new
# migration's SQL for real.
name: PostgreSQL Migration Tests
if: inputs.enable-pg-migrations
# Gate on the shared suite. Was needs: [test-backend] before the
# extraction; test-backend is no longer addressable from here, so gate
# on the aggregate tests job instead — otherwise PG migration tests run
# even when backend lint/type/unit tests have already failed.
needs: [tests]
runs-on: ${{ inputs.runner-os }}
timeout-minutes: 15
# Route consumer-supplied inputs through env so they reach the shell as
# data, never as expanded workflow expressions.
env:
PG_COMPOSE_FILE: ${{ inputs.pg-migrations-compose-file }}
PG_SERVICE: ${{ inputs.pg-migrations-service }}
PG_PYTEST_PATH: ${{ inputs.pg-migrations-pytest-path }}
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build test image (cached via gha)
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: ./backend
file: ./backend/Dockerfile.test
tags: ${{ inputs.pg-migrations-service }}:local
load: true
cache-from: type=gha,scope=pg-migrations
cache-to: type=gha,scope=pg-migrations,mode=max
- name: Bring up PostgreSQL sidecar
env:
MYGARAGE_TEST_UID: "1001"
MYGARAGE_TEST_GID: "1001"
run: |
docker compose -f "$PG_COMPOSE_FILE" \
-p "$PG_SERVICE" up -d postgres-test
- name: Wait for postgres healthy
run: |
for _ in $(seq 1 30); do
health=$(docker compose -f "$PG_COMPOSE_FILE" \
-p "$PG_SERVICE" ps postgres-test \
--format '{{.Health}}' || true)
if [ "$health" = "healthy" ]; then
echo "postgres-test healthy"
exit 0
fi
sleep 2
done
echo "postgres-test did not become healthy in 60s" >&2
docker compose -f "$PG_COMPOSE_FILE" \
-p "$PG_SERVICE" logs postgres-test
exit 1
- name: Run pytest against PG sidecar
env:
MYGARAGE_TEST_UID: "1001"
MYGARAGE_TEST_GID: "1001"
run: |
# Word-splitting on $PG_PYTEST_PATH is intentional: consumers may
# pass several space-separated test paths (mygarage adds
# tests/integration/).
# shellcheck disable=SC2086
docker compose -f "$PG_COMPOSE_FILE" \
-p "$PG_SERVICE" run --rm \
"$PG_SERVICE" \
pytest $PG_PYTEST_PATH -v --tb=short
- name: Tear down stack
if: always()
run: |
docker compose -f "$PG_COMPOSE_FILE" \
-p "$PG_SERVICE" down -v || true
docker-build-test:
name: Docker Build Test
runs-on: ${{ inputs.runner-os }}
timeout-minutes: 20
env:
BUILDKIT_PROGRESS: plain
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Read bun version
id: bun
env:
BUN_VERSION_FILE: ${{ inputs.bun-version-file }}
run: echo "version=$(cat "$BUN_VERSION_FILE")" >> "$GITHUB_OUTPUT"
- name: Build Docker image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
push: false
tags: ci-check:test
build-args: |
BUN_VERSION=${{ steps.bun.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: false