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
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ jobs:
with:
python-version: '3.12'
- run: npm ci
- name: Cache examples-chat python venv
uses: actions/cache@v4
with:
path: examples/chat/python/.venv
key: uv-venv-${{ runner.os }}-py3.12-${{ hashFiles('examples/chat/python/uv.lock') }}
- working-directory: examples/chat/python
run: uv sync
- run: npx nx run examples-chat-python:smoke --skip-nx-cache
Expand All @@ -260,8 +265,20 @@ jobs:
with:
python-version: '3.12'
- run: npm ci
- name: Cache examples-chat python venv
uses: actions/cache@v4
with:
path: examples/chat/python/.venv
key: uv-venv-${{ runner.os }}-py3.12-${{ hashFiles('examples/chat/python/uv.lock') }}
- working-directory: examples/chat/python
run: uv sync
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
playwright-${{ runner.os }}-
- run: npx playwright install --with-deps chromium
- run: npx nx e2e examples-chat-angular --skip-nx-cache -- --shard=${{ matrix.shard }}/4
- name: Upload Playwright trace on failure
Expand Down Expand Up @@ -333,9 +350,21 @@ jobs:
with:
python-version: '3.12'
- run: npm ci
- name: Cache cap python venv
uses: actions/cache@v4
with:
path: ${{ matrix.cap.python }}/.venv
key: uv-venv-${{ runner.os }}-py3.12-${{ matrix.cap.python }}-${{ hashFiles(format('{0}/uv.lock', matrix.cap.python)) }}
- name: uv sync per-cap python
working-directory: ${{ matrix.cap.python }}
run: uv sync
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
playwright-${{ runner.os }}-
- run: npx playwright install --with-deps chromium
- name: nx e2e ${{ matrix.cap.angular }}
run: npx nx e2e "${{ matrix.cap.angular }}" --skip-nx-cache
Expand Down Expand Up @@ -374,6 +403,13 @@ jobs:
node-version: 22
cache: npm
- run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
playwright-${{ runner.os }}-
- run: npx playwright install --with-deps chromium
- run: npx nx e2e website --skip-nx-cache

Expand Down Expand Up @@ -598,6 +634,14 @@ jobs:

echo "website=$website_changed" >> "$GITHUB_OUTPUT"
echo "cockpit=$cockpit_changed" >> "$GITHUB_OUTPUT"
- name: Cache Playwright browsers
if: steps.affected.outputs.website == 'true'
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
playwright-${{ runner.os }}-
- name: Install Playwright browsers
if: steps.affected.outputs.website == 'true'
run: npx playwright install --with-deps chromium
Expand Down Expand Up @@ -786,6 +830,13 @@ jobs:
run: npx tsx scripts/verify-shared-deployment.ts
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
playwright-${{ runner.os }}-
- run: npx playwright install --with-deps chromium
- name: Run production smoke tests
run: npx playwright test apps/cockpit/e2e/production-smoke.spec.ts --reporter=list
Expand Down
15 changes: 15 additions & 0 deletions scripts/ci-scope.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,21 @@ const GLOBAL_CI_FILES = new Set([
'nx.json',
'tsconfig.json',
'tsconfig.base.json',
]);

/** Files whose changes only affect linting (not builds, not e2e tests).
* These flip the scopes that actually run `nx lint` (library, cockpit,
* website, examples_chat) but do NOT trigger e2e/smoke/deploy jobs.
* Avoids the ~50 CI-minute spike from a one-line lint-config tweak
* re-running the 24-cap cockpit-e2e matrix. */
const LINT_ONLY_FILES = new Set([
'eslint.config.mjs',
]);

/** Subset of SCOPE_KEYS that own jobs running `nx lint`. Flipped true
* when a LINT_ONLY_FILES entry changes. */
const LINT_SCOPE_KEYS = ['library', 'cockpit', 'website', 'examples_chat'];

export function emptyScope() {
return Object.fromEntries(SCOPE_KEYS.map((k) => [k, false]));
}
Expand Down Expand Up @@ -58,6 +70,9 @@ export function classifyFromAffected(changedFiles, affectedProjects) {
if (SCOPE_KEYS.includes(key)) scope[key] = true;
}
}
if (changedFiles.some((f) => LINT_ONLY_FILES.has(f))) {
for (const key of LINT_SCOPE_KEYS) scope[key] = true;
}
return scope;
}

Expand Down
30 changes: 30 additions & 0 deletions scripts/ci-scope.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,36 @@ describe('classifyFromAffected β€” short-circuit', () => {
});
});

describe('classifyFromAffected β€” lint-only files', () => {
it('eslint.config.mjs flips only lint-running scopes, NOT e2e/smoke/deploy', () => {
const scope = classifyFromAffected(['eslint.config.mjs'], []);
// Lint-running scopes: true
assert.equal(scope.library, true);
assert.equal(scope.cockpit, true);
assert.equal(scope.website, true);
assert.equal(scope.examples_chat, true);
// E2e / smoke / deploy / secret / posthog scopes: false
assert.equal(scope.website_e2e, false);
assert.equal(scope.cockpit_e2e, false);
assert.equal(scope.cockpit_smoke, false);
assert.equal(scope.cockpit_examples, false);
assert.equal(scope.cockpit_secret, false);
assert.equal(scope.cockpit_deploy_smoke, false);
assert.equal(scope.posthog, false);
});

it('eslint.config.mjs alongside an affected project still ORs in the project scopes', () => {
const scope = classifyFromAffected(
['eslint.config.mjs', 'cockpit/chat/messages/python/src/graph.py'],
[{ name: 'cockpit-chat-messages-python', tags: ['scope:cockpit-e2e', 'scope:cockpit-examples', 'scope:cockpit-smoke'] }],
);
assert.equal(scope.library, true);
assert.equal(scope.cockpit_e2e, true);
assert.equal(scope.cockpit_examples, true);
assert.equal(scope.cockpit_smoke, true);
});
});

describe('classifyFromAffected β€” publishable lib broadcast', () => {
it('publishable lib triggers library + website + website_e2e + cockpit_* + examples_chat', () => {
const scope = classifyFromAffected(['libs/chat/src/foo.ts'], [
Expand Down
Loading