Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 29 additions & 27 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ jobs:
printf '%s=%s\n' "$key" "$value" >> "$GITHUB_OUTPUT"
echo "$key=$value"
done
- name: Validate CI workflow guards
run: node --test scripts/ci-workflow.spec.mjs

library:
name: Library — lint / test / build
Expand Down Expand Up @@ -445,16 +447,40 @@ jobs:

changed_files="$(git diff --name-only "$base_sha" "$head_sha")"
deploy_relevant=false
if printf '%s\n' "$changed_files" | grep -E '^(\.github/workflows/ci\.yml|vercel\.(json|cockpit\.json|examples\.json)|apps/(website|cockpit)/|cockpit/|examples/chat/|libs/|scripts/(assemble-examples|deploy-smoke|demo-middleware|langgraph-proxy|rate-limit)\.ts|scripts/assemble-demo\.ts)$' >/dev/null; then
if printf '%s\n' "$changed_files" | grep -E '^(\.github/workflows/ci\.yml|vercel\.(json|cockpit\.json|examples\.json)|apps/(website|cockpit)/.*|cockpit/.*|examples/chat/.*|libs/.*|scripts/(assemble-examples|deploy-smoke|demo-middleware|langgraph-proxy|rate-limit)\.ts|scripts/assemble-demo\.ts)$' >/dev/null; then
deploy_relevant=true
fi

echo "relevant=$deploy_relevant" >> "$GITHUB_OUTPUT"
if [ "$deploy_relevant" != "true" ]; then
echo "::notice::No deploy-relevant files changed; skipping Vercel dependency setup."
fi
# ── Angular examples deploy ──────────────────────────────────────────
- name: Check if examples changed
id: examples_changed
run: |
base_sha="${{ github.event.before }}"
head_sha="${{ github.sha }}"
if [ -z "$base_sha" ] || [ "$base_sha" = "0000000000000000000000000000000000000000" ]; then
base_sha="$(git rev-parse "$head_sha^")"
fi
changed_files="$(git diff --name-only "$base_sha" "$head_sha")"
examples_changed=false
if printf '%s\n' "$changed_files" | grep -E '^cockpit/.*/angular/' >/dev/null; then
examples_changed=true
fi
if printf '%s\n' "$changed_files" | grep -E '^(vercel\.examples\.json|scripts/assemble-examples\.ts)$' >/dev/null; then
examples_changed=true
fi
# Any libs/ change retriggers examples deploy. Previous hand-maintained
# allow-list silently broke whenever a new lib was added; cost of a
# spurious example rebuild is far cheaper than a missed deploy.
if printf '%s\n' "$changed_files" | grep -E '^libs/' >/dev/null; then
examples_changed=true
fi
echo "changed=$examples_changed" >> "$GITHUB_OUTPUT"
- uses: actions/setup-node@v6.3.0
if: steps.deploy_preflight.outputs.relevant == 'true'
if: steps.deploy_preflight.outputs.relevant == 'true' || steps.examples_changed.outputs.changed == 'true'
with:
node-version: 22
cache: npm
Expand All @@ -464,7 +490,7 @@ jobs:
# VERCEL_WEBSITE_PROJECT_ID — website project id
# VERCEL_COCKPIT_PROJECT_ID — cockpit project id
# VERCEL_EXAMPLES_PROJECT_ID — examples project id
- if: steps.deploy_preflight.outputs.relevant == 'true'
- if: steps.deploy_preflight.outputs.relevant == 'true' || steps.examples_changed.outputs.changed == 'true'
run: npm ci
- name: Resolve deploy targets
if: steps.deploy_preflight.outputs.relevant == 'true'
Expand Down Expand Up @@ -549,30 +575,6 @@ jobs:
run: |
npx tsx apps/cockpit/scripts/deploy-smoke.ts --url https://cockpit.cacheplane.ai --retries 20 --retry-delay-ms 5000

# ── Angular examples deploy ──────────────────────────────────────────
- name: Check if examples changed
id: examples_changed
run: |
base_sha="${{ github.event.before }}"
head_sha="${{ github.sha }}"
if [ -z "$base_sha" ] || [ "$base_sha" = "0000000000000000000000000000000000000000" ]; then
base_sha="$(git rev-parse "$head_sha^")"
fi
changed_files="$(git diff --name-only "$base_sha" "$head_sha")"
examples_changed=false
if printf '%s\n' "$changed_files" | grep -E '^cockpit/.*/angular/' >/dev/null; then
examples_changed=true
fi
if printf '%s\n' "$changed_files" | grep -E '^(vercel\.examples\.json|scripts/assemble-examples\.ts)$' >/dev/null; then
examples_changed=true
fi
# Any libs/ change retriggers examples deploy. Previous hand-maintained
# allow-list silently broke whenever a new lib was added; cost of a
# spurious example rebuild is far cheaper than a missed deploy.
if printf '%s\n' "$changed_files" | grep -E '^libs/' >/dev/null; then
examples_changed=true
fi
echo "changed=$examples_changed" >> "$GITHUB_OUTPUT"
- name: Build and assemble Angular examples
if: steps.examples_changed.outputs.changed == 'true'
run: npx tsx scripts/assemble-examples.ts
Expand Down
34 changes: 34 additions & 0 deletions scripts/ci-workflow.spec.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { readFile } from 'node:fs/promises';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';

describe('CI workflow', () => {
async function readDeployJob() {
const workflow = await readFile('.github/workflows/ci.yml', 'utf8');
return workflow.slice(
workflow.indexOf(' deploy:'),
workflow.indexOf(' demo-deploy:')
);
}

it('treats nested library files as deploy-relevant changes', async () => {
const deployJob = await readDeployJob();

const pattern = deployJob.match(/grep -E '([^']+)' >\/dev\/null/);

assert.match('libs/chat/src/lib/styles/chat-sidenav.styles.ts', new RegExp(pattern?.[1] ?? ''));
});

it('installs dependencies before assembling changed Angular examples', async () => {
const deployJob = await readDeployJob();

const dependencyInstall = deployJob.match(
/-\s+if:\s*(.+)\n\s+run:\s+npm ci/
);

assert.match(
dependencyInstall?.[1] ?? '',
/steps\.examples_changed\.outputs\.changed == 'true'/
);
});
});
Loading