Skip to content

Commit c620c12

Browse files
committed
chore(repo): add docker smoke tests
1 parent 7c1bbf4 commit c620c12

3 files changed

Lines changed: 808 additions & 0 deletions

File tree

.github/workflows/docker-smoke.yml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: Docker build and smoke test for apps
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
branches: ["preview"]
7+
paths:
8+
- "apps/web/**"
9+
- "apps/space/**"
10+
- "apps/admin/**"
11+
- "apps/live/**"
12+
- "packages/**"
13+
- "turbo.json"
14+
- "pnpm-lock.yaml"
15+
- "pnpm-workspace.yaml"
16+
- ".github/workflows/docker-smoke.yml"
17+
push:
18+
branches: ["preview"]
19+
paths:
20+
- "apps/web/**"
21+
- "apps/space/**"
22+
- "apps/admin/**"
23+
- "apps/live/**"
24+
- "packages/**"
25+
- "turbo.json"
26+
- "pnpm-lock.yaml"
27+
- "pnpm-workspace.yaml"
28+
- ".github/workflows/docker-smoke.yml"
29+
30+
concurrency:
31+
group: ${{ github.workflow }}-${{ github.ref }}
32+
cancel-in-progress: true
33+
34+
jobs:
35+
determine-matrix:
36+
name: Determine matrix
37+
runs-on: ubuntu-latest
38+
outputs:
39+
matrix: ${{ steps.build-matrix.outputs.matrix }}
40+
has_targets: ${{ steps.build-matrix.outputs.has_targets }}
41+
steps:
42+
- name: Checkout repository
43+
uses: actions/checkout@v4
44+
with:
45+
fetch-depth: 0
46+
47+
- name: Detect changed paths
48+
id: changes
49+
uses: dorny/paths-filter@v3
50+
with:
51+
filters: |
52+
web:
53+
- 'apps/web/**'
54+
space:
55+
- 'apps/space/**'
56+
admin:
57+
- 'apps/admin/**'
58+
live:
59+
- 'apps/live/**'
60+
common:
61+
- 'turbo.json'
62+
- 'pnpm-lock.yaml'
63+
- 'pnpm-workspace.yaml'
64+
- '.github/workflows/docker-smoke.yml'
65+
- 'packages/**'
66+
67+
- name: Build matrix
68+
id: build-matrix
69+
uses: actions/github-script@v7
70+
with:
71+
script: |
72+
const include = [];
73+
const eventName = context.eventName;
74+
const anyCommon = '${{ steps.changes.outputs.common }}' === 'true';
75+
const changed = {
76+
web: '${{ steps.changes.outputs.web }}' === 'true',
77+
space: '${{ steps.changes.outputs.space }}' === 'true',
78+
admin: '${{ steps.changes.outputs.admin }}' === 'true',
79+
live: '${{ steps.changes.outputs.live }}' === 'true',
80+
};
81+
const add = (name, dockerfile, image, container, port, path, env_flags = "") => include.push({ name, dockerfile, image, container, host_port: port, path, env_flags });
82+
const buildAll = anyCommon || eventName === 'push' || eventName === 'workflow_dispatch';
83+
if (buildAll || changed.web) add('web', 'apps/web/Dockerfile.web', 'plane-web:ci-smoke', 'plane-web-ci', 3001, '/');
84+
if (buildAll || changed.space) add('space', 'apps/space/Dockerfile.space', 'plane-space:ci-smoke', 'plane-space-ci', 3002, '/spaces');
85+
if (buildAll || changed.admin) add('admin', 'apps/admin/Dockerfile.admin', 'plane-admin:ci-smoke', 'plane-admin-ci', 3003, '/god-mode');
86+
if (buildAll || changed.live) add('live', 'apps/live/Dockerfile.live', 'plane-live:ci-smoke', 'plane-live-ci', 3004, '/live/health', '-e NODE_ENV=production -e LIVE_BASE_PATH=/live');
87+
const hasTargets = include.length > 0;
88+
if (!hasTargets) {
89+
core.warning('No changes detected for any app. Matrix is empty. Skipping smoke tests.');
90+
}
91+
core.setOutput('matrix', JSON.stringify({ include }));
92+
core.setOutput('has_targets', String(hasTargets));
93+
smoke:
94+
name: Build and smoke test ${{ matrix.name }}
95+
runs-on: ubuntu-latest
96+
needs: determine-matrix
97+
if: ${{ needs.determine-matrix.outputs.has_targets == 'true' }}
98+
timeout-minutes: 25
99+
100+
strategy:
101+
fail-fast: false
102+
matrix: ${{ fromJSON(needs.determine-matrix.outputs.matrix) }}
103+
104+
steps:
105+
- name: Checkout repository
106+
uses: actions/checkout@v4
107+
with:
108+
fetch-depth: 0
109+
110+
- name: Show Docker version
111+
run: |
112+
docker version
113+
docker info
114+
115+
- name: Build image (${{ matrix.name }})
116+
working-directory: .
117+
run: |
118+
docker build --pull -f ${{ matrix.dockerfile }} -t ${{ matrix.image }} .
119+
120+
- name: Run container (${{ matrix.name }})
121+
run: |
122+
docker run -d --name ${{ matrix.container }} -p ${{ matrix.host_port }}:3000 ${{ matrix.env_flags }} ${{ matrix.image }}
123+
docker ps -a
124+
125+
- name: Smoke test HTTP endpoint (${{ matrix.name }})
126+
shell: bash
127+
run: |
128+
set -euo pipefail
129+
URL="http://localhost:${{ matrix.host_port }}${{ matrix.path }}"
130+
echo "Probing $URL ..."
131+
# Try up to at least ~120 seconds (60 attempts * 2s), plus per-request time
132+
for i in {1..60}; do
133+
STATUS="$(curl --connect-timeout 2 --max-time 5 -sS -o /dev/null -w "%{http_code}" -L "${URL}" || true)"
134+
case "${STATUS}" in
135+
2??|3??)
136+
echo "Success: HTTP ${STATUS} from ${URL}"
137+
exit 0
138+
;;
139+
esac
140+
echo "Attempt ${i}: HTTP ${STATUS} (waiting 2s)"
141+
sleep 2
142+
done
143+
echo "Failed to get a 2xx/3xx response from ${URL}"
144+
echo "::group::Container logs (${{ matrix.container }})"
145+
docker logs ${{ matrix.container }} || true
146+
echo "::endgroup::"
147+
exit 1
148+
149+
- name: Cleanup container (${{ matrix.name }})
150+
if: always()
151+
run: |
152+
docker rm -f ${{ matrix.container }} || true

0 commit comments

Comments
 (0)