ci: consolidate workflows into single CI pipeline with job deps
CI / Assistant Split Regression (push) Failing after 5m21s
CI / Architecture Guardrails (push) Failing after 5m28s
CI / Unit Tests (push) Failing after 27s
CI / Typecheck (push) Failing after 8m39s
CI / Build (push) Has been skipped
CI / E2E Tests (push) Has been skipped
CI / Lint (push) Successful in 9m32s
CI / Release Images (push) Has been skipped
CI / Fresh-Linux Docker Deploy (push) Has been skipped
CI / Assistant Split Regression (push) Failing after 5m21s
CI / Architecture Guardrails (push) Failing after 5m28s
CI / Unit Tests (push) Failing after 27s
CI / Typecheck (push) Failing after 8m39s
CI / Build (push) Has been skipped
CI / E2E Tests (push) Has been skipped
CI / Lint (push) Successful in 9m32s
CI / Release Images (push) Has been skipped
CI / Fresh-Linux Docker Deploy (push) Has been skipped
Collapses ci.yml, release-image.yml, and deploy-test.yml from three parallel push-triggered workflows into one orchestrated pipeline: - release-image.yml: converted to reusable workflow (workflow_call + workflow_dispatch). No longer triggers on push directly. - deploy-test.yml: deleted, content inlined into ci.yml as the docker-deploy-test job with needs: [build]. - ci.yml: adds docker-deploy-test job and release-images job. The release-images job calls release-image.yml via uses: and is gated to push events on main, so PRs do not publish images. - check-architecture-guardrails.mjs: updated to enforce the new reusable-workflow shape (workflow_call trigger, ci.yml chains release-image.yml, main-push gating). One run per commit, clear Success/Failure status, no wasted image builds when CI fails. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -360,3 +360,98 @@ jobs:
|
||||
name: playwright-report
|
||||
path: apps/web/playwright-report/
|
||||
retention-days: 14
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Fresh Docker Compose deploy test — validates
|
||||
# that the prod compose bundle comes up clean
|
||||
# from scratch and the smoke tests pass.
|
||||
# ──────────────────────────────────────────────
|
||||
docker-deploy-test:
|
||||
name: Fresh-Linux Docker Deploy
|
||||
needs: [build]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create minimal .env
|
||||
run: |
|
||||
cat <<'EOF' > .env
|
||||
NEXTAUTH_URL=http://localhost:3100
|
||||
NEXTAUTH_SECRET=ci-test-secret-minimum-32-chars-xx
|
||||
PGADMIN_PASSWORD=ci-pgadmin
|
||||
EOF
|
||||
|
||||
- name: Start infrastructure (postgres + redis)
|
||||
run: docker compose up -d postgres redis
|
||||
|
||||
- name: Wait for postgres
|
||||
run: |
|
||||
for i in $(seq 1 20); do
|
||||
docker compose exec -T postgres pg_isready -U capakraken -d capakraken && break
|
||||
sleep 3
|
||||
done
|
||||
|
||||
- name: Build and start app (full profile)
|
||||
run: docker compose --profile full up -d --build app
|
||||
|
||||
- name: Wait for /api/health (up to 3 minutes)
|
||||
run: |
|
||||
for i in $(seq 1 36); do
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3100/api/health || echo "000")
|
||||
echo "Attempt $i: HTTP $STATUS"
|
||||
if [ "$STATUS" = "200" ]; then exit 0; fi
|
||||
sleep 5
|
||||
done
|
||||
echo "Health check timed out"
|
||||
docker compose logs app --tail=50
|
||||
exit 1
|
||||
|
||||
- name: Verify health response contains status ok
|
||||
run: |
|
||||
BODY=$(curl -sf http://localhost:3100/api/health)
|
||||
echo "$BODY"
|
||||
echo "$BODY" | grep '"status":"ok"'
|
||||
|
||||
- name: Seed admin user
|
||||
run: |
|
||||
docker compose exec -T app node /app/scripts/setup-admin.mjs \
|
||||
--email admin@capakraken.dev \
|
||||
--name "Admin" \
|
||||
--password admin123
|
||||
|
||||
- name: Set up Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install Playwright and Chromium
|
||||
run: |
|
||||
npm install -g @playwright/test@1.49
|
||||
playwright install chromium --with-deps
|
||||
|
||||
- name: Run smoke tests
|
||||
run: npx playwright test --config apps/web/playwright.ci.config.ts
|
||||
|
||||
- name: Upload Playwright report
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-smoke-report
|
||||
path: apps/web/playwright-report/
|
||||
retention-days: 7
|
||||
|
||||
- name: Show logs on failure
|
||||
if: failure()
|
||||
run: docker compose logs --tail=100
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Release images — only on push to main, after
|
||||
# every check has passed. Calls the reusable
|
||||
# release-image.yml workflow.
|
||||
# ──────────────────────────────────────────────
|
||||
release-images:
|
||||
name: Release Images
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
needs: [lint, test, e2e, assistant-split, docker-deploy-test]
|
||||
uses: ./.github/workflows/release-image.yml
|
||||
secrets: inherit
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
name: Docker Deploy Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- ".gitea/**"
|
||||
- "**/*.md"
|
||||
- "LICENSE"
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- ".gitea/**"
|
||||
- "**/*.md"
|
||||
- "LICENSE"
|
||||
|
||||
concurrency:
|
||||
group: deploy-test-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docker-deploy-test:
|
||||
name: Fresh-Linux Docker Deploy
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create minimal .env
|
||||
run: |
|
||||
cat <<'EOF' > .env
|
||||
NEXTAUTH_URL=http://localhost:3100
|
||||
NEXTAUTH_SECRET=ci-test-secret-minimum-32-chars-xx
|
||||
PGADMIN_PASSWORD=ci-pgadmin
|
||||
EOF
|
||||
|
||||
- name: Start infrastructure (postgres + redis)
|
||||
run: docker compose up -d postgres redis
|
||||
|
||||
- name: Wait for postgres
|
||||
run: |
|
||||
for i in $(seq 1 20); do
|
||||
docker compose exec -T postgres pg_isready -U capakraken -d capakraken && break
|
||||
sleep 3
|
||||
done
|
||||
|
||||
- name: Build and start app (full profile)
|
||||
run: docker compose --profile full up -d --build app
|
||||
|
||||
- name: Wait for /api/health (up to 3 minutes)
|
||||
run: |
|
||||
for i in $(seq 1 36); do
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3100/api/health || echo "000")
|
||||
echo "Attempt $i: HTTP $STATUS"
|
||||
if [ "$STATUS" = "200" ]; then exit 0; fi
|
||||
sleep 5
|
||||
done
|
||||
echo "Health check timed out"
|
||||
docker compose logs app --tail=50
|
||||
exit 1
|
||||
|
||||
- name: Verify health response contains status ok
|
||||
run: |
|
||||
BODY=$(curl -sf http://localhost:3100/api/health)
|
||||
echo "$BODY"
|
||||
echo "$BODY" | grep '"status":"ok"'
|
||||
|
||||
- name: Seed admin user
|
||||
run: |
|
||||
docker compose exec -T app node /app/scripts/setup-admin.mjs \
|
||||
--email admin@capakraken.dev \
|
||||
--name "Admin" \
|
||||
--password admin123
|
||||
|
||||
- name: Set up Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install Playwright and Chromium
|
||||
run: |
|
||||
npm install -g @playwright/test@1.49
|
||||
playwright install chromium --with-deps
|
||||
|
||||
- name: Run smoke tests
|
||||
run: npx playwright test --config apps/web/playwright.ci.config.ts
|
||||
|
||||
- name: Upload Playwright report
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-smoke-report
|
||||
path: apps/web/playwright-report/
|
||||
retention-days: 7
|
||||
|
||||
- name: Show logs on failure
|
||||
if: failure()
|
||||
run: docker compose logs --tail=100
|
||||
@@ -1,13 +1,19 @@
|
||||
name: Release Image
|
||||
|
||||
# Reusable workflow: called from ci.yml after all checks pass.
|
||||
# Can also be dispatched manually for rebuilds or tag overrides.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- ".gitea/**"
|
||||
- "**/*.md"
|
||||
- "LICENSE"
|
||||
workflow_call:
|
||||
inputs:
|
||||
image_tag:
|
||||
description: Optional tag override, defaults to sha-<commit>
|
||||
required: false
|
||||
type: string
|
||||
secrets:
|
||||
GHCR_USERNAME:
|
||||
required: true
|
||||
GHCR_TOKEN:
|
||||
required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
image_tag:
|
||||
|
||||
@@ -663,8 +663,8 @@ export const rules = [
|
||||
file: ".github/workflows/release-image.yml",
|
||||
required: [
|
||||
{
|
||||
pattern: /push:\s*\n\s*branches:\s*\[main\]/,
|
||||
message: "image releases must build automatically on pushes to main",
|
||||
pattern: /workflow_call:/,
|
||||
message: "release workflow must remain callable as a reusable workflow from ci.yml",
|
||||
},
|
||||
{
|
||||
pattern: /workflow_dispatch:/,
|
||||
@@ -708,6 +708,14 @@ export const rules = [
|
||||
pattern: /run:\s+pnpm db:generate/,
|
||||
message: "CI must route Prisma client generation through the workspace env/schema wrapper",
|
||||
},
|
||||
{
|
||||
pattern: /uses:\s+\.\/\.github\/workflows\/release-image\.yml/,
|
||||
message: "ci.yml must chain release-image.yml so image builds run after checks pass",
|
||||
},
|
||||
{
|
||||
pattern: /github\.event_name == 'push' && github\.ref == 'refs\/heads\/main'/,
|
||||
message: "release-images job must be gated to main-branch pushes to avoid PR image pushes",
|
||||
},
|
||||
],
|
||||
forbidden: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user