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
|
name: playwright-report
|
||||||
path: apps/web/playwright-report/
|
path: apps/web/playwright-report/
|
||||||
retention-days: 14
|
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
|
name: Release Image
|
||||||
|
|
||||||
|
# Reusable workflow: called from ci.yml after all checks pass.
|
||||||
|
# Can also be dispatched manually for rebuilds or tag overrides.
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_call:
|
||||||
branches: [main]
|
inputs:
|
||||||
paths-ignore:
|
image_tag:
|
||||||
- "docs/**"
|
description: Optional tag override, defaults to sha-<commit>
|
||||||
- ".gitea/**"
|
required: false
|
||||||
- "**/*.md"
|
type: string
|
||||||
- "LICENSE"
|
secrets:
|
||||||
|
GHCR_USERNAME:
|
||||||
|
required: true
|
||||||
|
GHCR_TOKEN:
|
||||||
|
required: true
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
image_tag:
|
image_tag:
|
||||||
|
|||||||
@@ -663,8 +663,8 @@ export const rules = [
|
|||||||
file: ".github/workflows/release-image.yml",
|
file: ".github/workflows/release-image.yml",
|
||||||
required: [
|
required: [
|
||||||
{
|
{
|
||||||
pattern: /push:\s*\n\s*branches:\s*\[main\]/,
|
pattern: /workflow_call:/,
|
||||||
message: "image releases must build automatically on pushes to main",
|
message: "release workflow must remain callable as a reusable workflow from ci.yml",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pattern: /workflow_dispatch:/,
|
pattern: /workflow_dispatch:/,
|
||||||
@@ -708,6 +708,14 @@ export const rules = [
|
|||||||
pattern: /run:\s+pnpm db:generate/,
|
pattern: /run:\s+pnpm db:generate/,
|
||||||
message: "CI must route Prisma client generation through the workspace env/schema wrapper",
|
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: [
|
forbidden: [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user