refactor: split smoke and integration test configs into separate CI jobs (#264)

* refactor: split smoke and integration test configs into separate CI jobs

* fix: move CLA labeling from triage to CLA workflow

* fix: install formatters in temp dir to avoid catalog: protocol error

* fix: handle 404 when removing labels that don't exist on the PR
This commit is contained in:
Matt Kane
2026-04-05 08:22:17 +01:00
committed by GitHub
parent c4977e1fd1
commit 5beb0ddc33
8 changed files with 97 additions and 71 deletions

View File

@@ -56,20 +56,13 @@ jobs:
ref: ${{ steps.pr.outputs.sha }}
persist-credentials: false
# --- Install formatters directly (no pnpm install, no postinstall scripts) ---
- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22
- name: Install formatters
run: npm install --no-save --ignore-scripts oxfmt prettier prettier-plugin-astro
- name: Run formatters
run: |
npx oxfmt --ignore-path .gitignore
npx prettier --write .
- name: Run formatter
run: npx oxfmt --ignore-path .gitignore
- name: Check for changes
id: diff
@@ -125,5 +118,5 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ steps.pr.outputs.number }},
body: `Could not push formatting changes to this fork. The contributor may have "Allow edits by maintainers" disabled.\n\nPlease run the formatter locally:\n\n\`\`\`\nnpx oxfmt --ignore-path .gitignore\nnpx prettier --write .\n\`\`\``,
body: `Could not push formatting changes to this fork. The contributor may have "Allow edits by maintainers" disabled.\n\nPlease run the formatter locally:\n\n\`\`\`\npnpm format\n\`\`\``,
});

View File

@@ -118,7 +118,7 @@ jobs:
test-smoke:
name: Smoke Tests
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
services:
postgres:
image: postgres:17
@@ -144,10 +144,26 @@ jobs:
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm --filter emdash exec vitest run --config vitest.smoke.config.ts
timeout-minutes: 5
env:
DATABASE_URL: postgres://postgres:test@localhost:5432/emdash_smoke
test-integration:
name: Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm --filter emdash exec vitest run --config vitest.integration.config.ts
test-browser:
name: Browser Tests
runs-on: ubuntu-latest

View File

@@ -27,3 +27,47 @@ jobs:
branch: "cla-signatures"
allowlist: dependabot[bot]
lock-pullrequest-aftermerge: false
- name: Label CLA status
if: always() && (github.event_name == 'pull_request_target' || github.event.issue.pull_request)
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const prNumber = context.payload.pull_request?.number || context.payload.issue?.number;
if (!prNumber) return;
const owner = context.repo.owner;
const repo = context.repo.repo;
// Get the PR to read head SHA
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
// Read the CLA commit status
const { data: statuses } = await github.rest.repos.listCommitStatusesForRef({
owner, repo, ref: pr.head.sha,
});
const claStatus = statuses.find(s => s.context === 'license/cla');
if (!claStatus) return;
const signed = claStatus.state === 'success';
const addLabel = signed ? 'cla: signed' : 'cla: needed';
const removeLabel = signed ? 'cla: needed' : 'cla: signed';
// Ensure labels exist
const labelColors = { 'cla: signed': '0e8a16', 'cla: needed': 'b60205' };
try {
await github.rest.issues.getLabel({ owner, repo, name: addLabel });
} catch {
await github.rest.issues.createLabel({ owner, repo, name: addLabel, color: labelColors[addLabel] });
}
// Add the correct label
const currentLabels = pr.labels.map(l => l.name);
if (!currentLabels.includes(addLabel)) {
await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: [addLabel] });
}
// Remove the stale label
if (currentLabels.includes(removeLabel)) {
await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: removeLabel });
}

View File

@@ -77,13 +77,8 @@ jobs:
with:
node-version: 22
- name: Install formatters
run: npm install --no-save --ignore-scripts oxfmt prettier prettier-plugin-astro
- name: Run formatters
run: |
npx oxfmt --ignore-path .gitignore
npx prettier --write .
- name: Run formatter
run: npx oxfmt --ignore-path .gitignore
- name: Check for changes
id: diff
@@ -133,7 +128,7 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Could not push formatting changes to this fork. The contributor may have "Allow edits by maintainers" disabled.\n\nPlease run the formatter locally:\n\n\`\`\`\nnpx oxfmt --ignore-path .gitignore\nnpx prettier --write .\n\`\`\``,
body: `Could not push formatting changes to this fork. The contributor may have "Allow edits by maintainers" disabled.\n\nPlease run the formatter locally:\n\n\`\`\`\npnpm format\n\`\`\``,
});
- name: React to comment (result)

View File

@@ -81,29 +81,7 @@ jobs:
// Ignore -- mergeable state may not be computed yet
}
// --- CLA status ---
// The CLA assistant sets a commit status named "license/cla".
// Check the latest status for this PR's head SHA.
try {
const { data: statuses } = await github.rest.repos.listCommitStatusesForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: pr.head.sha,
});
const claStatus = statuses.find(s => s.context === 'license/cla');
if (claStatus) {
if (claStatus.state === 'success') {
labels.add('cla: signed');
} else {
labels.add('cla: needed');
}
} else {
// CLA check hasn't run yet -- mark as pending
labels.add('cla: needed');
}
} catch {
// If we can't read statuses, don't add CLA labels
}
// CLA labels are managed by the CLA workflow (cla.yml), not here.
// --- Ensure all labels exist, then apply ---
const labelColors = {
@@ -121,8 +99,6 @@ jobs:
'area/ci': '000000',
'area/auth': 'd4c5f9',
'area/cloudflare': 'f9a825',
'cla: signed': '0e8a16',
'cla: needed': 'b60205',
'needs-rebase': 'e11d48',
};
@@ -152,39 +128,30 @@ jobs:
// Get current labels on the PR to remove stale ones
const currentLabels = new Set(pr.labels.map(l => l.name));
// Remove stale size labels (only one size label at a time)
for (const sl of sizeLabels) {
if (sl !== sizeLabel && currentLabels.has(sl)) {
// Helper: remove a label, ignoring 404 if it's already gone
async function safeRemoveLabel(name) {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
name: sl,
name,
});
} catch (e) {
if (e.status !== 404) throw e;
}
}
// Remove stale CLA labels
const claLabels = ['cla: signed', 'cla: needed'];
for (const cl of claLabels) {
if (!labels.has(cl) && currentLabels.has(cl)) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
name: cl,
});
// Remove stale size labels (only one size label at a time)
for (const sl of sizeLabels) {
if (sl !== sizeLabel && currentLabels.has(sl)) {
await safeRemoveLabel(sl);
}
}
// Remove needs-rebase if PR is now mergeable
if (!labels.has('needs-rebase') && currentLabels.has('needs-rebase')) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
name: 'needs-rebase',
});
await safeRemoveLabel('needs-rebase');
}
// Add new labels

View File

@@ -150,7 +150,8 @@
"typecheck": "tsgo --noEmit",
"check": "publint && attw --pack --ignore-rules=cjs-resolves-to-esm --ignore-rules=no-resolution --ignore-rules=internal-resolution-error",
"test": "vitest",
"test:smoke": "vitest run --config vitest.smoke.config.ts"
"test:smoke": "vitest run --config vitest.smoke.config.ts",
"test:integration": "vitest run --config vitest.integration.config.ts"
},
"dependencies": {
"@emdash-cms/admin": "workspace:*",

View File

@@ -0,0 +1,14 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
include: ["tests/integration/cli/**/*.test.ts", "tests/integration/client/**/*.test.ts"],
// These tests boot real Astro dev servers in beforeAll hooks.
// Default hookTimeout (10s) is too short -- server startup +
// migrations + seed can take 30-60s.
testTimeout: 30_000,
hookTimeout: 120_000,
},
});

View File

@@ -4,11 +4,7 @@ export default defineConfig({
test: {
globals: true,
environment: "node",
include: [
"tests/integration/smoke/**/*.test.ts",
"tests/integration/cli/**/*.test.ts",
"tests/integration/client/**/*.test.ts",
],
include: ["tests/integration/smoke/**/*.test.ts"],
// Smoke tests boot real Astro dev servers in beforeAll hooks.
// Default hookTimeout (10s) is too short -- server startup +
// migrations + seed can take 30-60s, especially on first run