ee3270ce1c
Covers the "Node.js 20 is deprecated" warning emitted by actions/checkout, actions/setup-node, actions/cache, actions/upload-artifact and actions/download-artifact on their older releases. Every bumped line carries an inline `# kilocode_change` marker since these workflow files are shared with upstream OpenCode. When upstream bumps its own action versions we just drop the markers on merge.
394 lines
16 KiB
YAML
394 lines
16 KiB
YAML
name: Visual Regression Tests
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened]
|
|
|
|
jobs:
|
|
check-paths:
|
|
name: Check changed paths
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
matched: ${{ steps.filter.outputs.matched }}
|
|
is_fork: ${{ steps.fork-check.outputs.is_fork }}
|
|
steps:
|
|
- uses: actions/checkout@v6 # kilocode_change
|
|
- uses: Kilo-Org/paths-filter@master
|
|
id: filter
|
|
with:
|
|
filters: |
|
|
matched:
|
|
- "packages/kilo-ui/**"
|
|
- "packages/ui/**"
|
|
- "packages/util/**"
|
|
- "packages/sdk/js/**"
|
|
- "packages/kilo-vscode/webview-ui/**"
|
|
- "packages/kilo-vscode/.storybook/**"
|
|
- "packages/kilo-vscode/tests/visual-regression*"
|
|
- "packages/kilo-vscode/tests/permission-dock-dropdown*"
|
|
- "packages/kilo-docs/public/img/screenshot-tests/**"
|
|
- ".github/workflows/visual-regression.yml"
|
|
- name: Check if PR is from a fork
|
|
id: fork-check
|
|
run: |
|
|
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
|
|
echo "is_fork=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "is_fork=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
visual-regression:
|
|
needs: check-paths
|
|
if: needs.check-paths.outputs.matched == 'true'
|
|
name: Visual Regression (kilo-ui)
|
|
runs-on: blacksmith-4vcpu-ubuntu-2404
|
|
timeout-minutes: 15
|
|
|
|
steps:
|
|
- name: Checkout (internal)
|
|
if: needs.check-paths.outputs.is_fork != 'true'
|
|
uses: actions/checkout@v6 # kilocode_change
|
|
with:
|
|
lfs: true
|
|
token: ${{ secrets.BOT_PAT }}
|
|
ref: ${{ github.head_ref }}
|
|
|
|
- name: Checkout (fork)
|
|
if: needs.check-paths.outputs.is_fork == 'true'
|
|
uses: actions/checkout@v6 # kilocode_change
|
|
with:
|
|
lfs: true
|
|
|
|
- name: Check if HEAD is a baseline update commit
|
|
if: needs.check-paths.outputs.is_fork != 'true'
|
|
id: check-baseline-commit
|
|
run: |
|
|
COMMIT_MSG=$(git log -1 --format=%s)
|
|
if [ "$COMMIT_MSG" = "chore: update visual regression baselines" ] || [ "$COMMIT_MSG" = "chore: update kilo-vscode visual regression baselines" ]; then
|
|
echo "is_baseline_update=true" >> "$GITHUB_OUTPUT"
|
|
echo "HEAD commit is a baseline update commit — will not auto-commit again."
|
|
else
|
|
echo "is_baseline_update=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v2
|
|
with:
|
|
bun-version: latest
|
|
|
|
- name: Cache Bun modules
|
|
uses: actions/cache@v5 # kilocode_change
|
|
with:
|
|
path: ~/.bun/install/cache
|
|
key: bun-${{ hashFiles('bun.lock') }}
|
|
|
|
- name: Install dependencies
|
|
run: bun install
|
|
|
|
- name: Cache Playwright browsers
|
|
id: playwright-cache
|
|
uses: actions/cache@v5 # kilocode_change
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ hashFiles('packages/kilo-ui/package.json') }}
|
|
|
|
- name: Install Playwright browsers
|
|
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
|
run: bunx playwright install chromium
|
|
working-directory: packages/kilo-ui
|
|
|
|
- name: Install Playwright system deps
|
|
run: bunx playwright install-deps chromium
|
|
working-directory: packages/kilo-ui
|
|
|
|
- name: Cache Storybook build
|
|
id: storybook-cache
|
|
uses: actions/cache@v5 # kilocode_change
|
|
with:
|
|
path: packages/kilo-ui/storybook-static
|
|
key: storybook-${{ hashFiles('packages/kilo-ui/src/**', 'packages/kilo-ui/.storybook/**', 'packages/ui/src/**', 'packages/kilo-ui/package.json') }}
|
|
|
|
- name: Build Storybook
|
|
if: steps.storybook-cache.outputs.cache-hit != 'true'
|
|
run: bun run build-storybook
|
|
working-directory: packages/kilo-ui
|
|
|
|
- name: Generate baselines for new/missing stories
|
|
run: bun run test:visual:update
|
|
working-directory: packages/kilo-ui
|
|
env:
|
|
CI: true
|
|
PLAYWRIGHT_WORKERS: "4"
|
|
|
|
- name: Remove stale baselines for deleted stories
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs'), path = require('path');
|
|
const idx = JSON.parse(fs.readFileSync('storybook-static/index.json', 'utf8'));
|
|
const stories = Object.values(idx.entries || idx.stories || {}).filter(s => s.id && !s.id.endsWith('--docs'));
|
|
const expected = new Set(stories.map(s => { const [c,v] = s.id.split('--'); return c + '/' + v + '-chromium-linux.png'; }));
|
|
const dir = '../kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression';
|
|
if (!fs.existsSync(dir)) process.exit(0);
|
|
for (const component of fs.readdirSync(dir)) {
|
|
const cdir = path.join(dir, component);
|
|
if (!fs.statSync(cdir).isDirectory()) continue;
|
|
for (const file of fs.readdirSync(cdir)) {
|
|
const rel = component + '/' + file;
|
|
if (file.endsWith('.png') && !expected.has(rel)) { console.log('Removing stale baseline:', rel); fs.unlinkSync(path.join(cdir, file)); }
|
|
}
|
|
}
|
|
"
|
|
working-directory: packages/kilo-ui
|
|
|
|
- name: Check for baseline changes (fork PRs)
|
|
if: needs.check-paths.outputs.is_fork == 'true'
|
|
run: |
|
|
git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/
|
|
if git diff --cached --quiet; then
|
|
echo "No visual regression detected."
|
|
else
|
|
echo "::error::Visual regression detected. Screenshot baselines have changed."
|
|
echo "::error::Since this PR is from a fork, updated screenshots cannot be committed automatically."
|
|
echo "::error::Please ask a Kilo developer for help updating the screenshots."
|
|
git diff --cached --stat
|
|
exit 1
|
|
fi
|
|
|
|
- name: Fail if baselines still changing after auto-update
|
|
if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit.outputs.is_baseline_update == 'true'
|
|
run: |
|
|
git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/
|
|
if git diff --cached --quiet; then
|
|
echo "Baselines are stable after auto-update."
|
|
else
|
|
echo "::error::Visual regression baselines changed again after a previous auto-update commit."
|
|
echo "::error::This indicates non-deterministic screenshots that would cause an infinite update loop."
|
|
echo "::error::Please investigate the flaky screenshots and add non-deterministic stories to the SKIP set."
|
|
git diff --cached --stat
|
|
exit 1
|
|
fi
|
|
|
|
- name: Commit and push new baselines (if any)
|
|
if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit.outputs.is_baseline_update != 'true'
|
|
id: commit-baselines
|
|
env:
|
|
GH_TOKEN: ${{ secrets.BOT_PAT }}
|
|
run: |
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/
|
|
if git diff --cached --quiet; then
|
|
echo "No new baselines — nothing to commit."
|
|
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
git commit -m "chore: update visual regression baselines"
|
|
git lfs push --all origin
|
|
git push --no-verify
|
|
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Fail if baselines changed
|
|
if: needs.check-paths.outputs.is_fork != 'true' && steps.commit-baselines.outputs.changed == 'true'
|
|
run: |
|
|
echo "::error::Visual regression baselines changed. New baselines have been committed to the branch. Please pull and review."
|
|
exit 1
|
|
|
|
- name: Upload test results on failure
|
|
if: failure()
|
|
uses: actions/upload-artifact@v7 # kilocode_change
|
|
with:
|
|
name: visual-regression-results
|
|
path: packages/kilo-ui/test-results/
|
|
retention-days: 7
|
|
|
|
visual-regression-vscode:
|
|
needs: check-paths
|
|
if: needs.check-paths.outputs.matched == 'true'
|
|
name: Visual Regression (kilo-vscode webview)
|
|
runs-on: blacksmith-4vcpu-ubuntu-2404
|
|
timeout-minutes: 15
|
|
|
|
steps:
|
|
- name: Checkout (internal)
|
|
if: needs.check-paths.outputs.is_fork != 'true'
|
|
uses: actions/checkout@v6 # kilocode_change
|
|
with:
|
|
lfs: true
|
|
token: ${{ secrets.BOT_PAT }}
|
|
ref: ${{ github.head_ref }}
|
|
|
|
- name: Checkout (fork)
|
|
if: needs.check-paths.outputs.is_fork == 'true'
|
|
uses: actions/checkout@v6 # kilocode_change
|
|
with:
|
|
lfs: true
|
|
|
|
- name: Check if HEAD is a baseline update commit
|
|
if: needs.check-paths.outputs.is_fork != 'true'
|
|
id: check-baseline-commit-vscode
|
|
run: |
|
|
COMMIT_MSG=$(git log -1 --format=%s)
|
|
if [ "$COMMIT_MSG" = "chore: update visual regression baselines" ] || [ "$COMMIT_MSG" = "chore: update kilo-vscode visual regression baselines" ]; then
|
|
echo "is_baseline_update=true" >> "$GITHUB_OUTPUT"
|
|
echo "HEAD commit is a baseline update commit — will not auto-commit again."
|
|
else
|
|
echo "is_baseline_update=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v2
|
|
with:
|
|
bun-version: latest
|
|
|
|
- name: Cache Bun modules
|
|
uses: actions/cache@v5 # kilocode_change
|
|
with:
|
|
path: ~/.bun/install/cache
|
|
key: bun-${{ hashFiles('bun.lock') }}
|
|
|
|
- name: Install dependencies
|
|
run: bun install
|
|
|
|
- name: Cache Playwright browsers
|
|
id: playwright-cache-vscode
|
|
uses: actions/cache@v5 # kilocode_change
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-vscode-${{ hashFiles('packages/kilo-vscode/package.json') }}
|
|
|
|
- name: Install Playwright browsers
|
|
if: steps.playwright-cache-vscode.outputs.cache-hit != 'true'
|
|
run: bunx playwright install chromium
|
|
working-directory: packages/kilo-vscode
|
|
|
|
- name: Install Playwright system deps
|
|
run: bunx playwright install-deps chromium
|
|
working-directory: packages/kilo-vscode
|
|
|
|
- name: Cache Storybook build
|
|
id: storybook-cache-vscode
|
|
uses: actions/cache@v5 # kilocode_change
|
|
with:
|
|
path: packages/kilo-vscode/storybook-static
|
|
key: storybook-vscode-${{ hashFiles('packages/kilo-vscode/webview-ui/src/**', 'packages/kilo-vscode/.storybook/**', 'packages/kilo-ui/src/**', 'packages/ui/src/**', 'packages/kilo-vscode/package.json') }}
|
|
|
|
- name: Build Storybook
|
|
if: steps.storybook-cache-vscode.outputs.cache-hit != 'true'
|
|
run: bun run build-storybook
|
|
working-directory: packages/kilo-vscode
|
|
|
|
- name: Generate baselines for new/missing stories
|
|
run: bun run test:visual:update
|
|
working-directory: packages/kilo-vscode
|
|
env:
|
|
CI: true
|
|
PLAYWRIGHT_WORKERS: "4"
|
|
|
|
- name: Remove stale baselines for deleted stories
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs'), path = require('path');
|
|
const idx = JSON.parse(fs.readFileSync('storybook-static/index.json', 'utf8'));
|
|
const stories = Object.values(idx.entries || idx.stories || {}).filter(s => s.id && !s.id.endsWith('--docs'));
|
|
const expected = new Set(stories.map(s => { const [c,v] = s.id.split('--'); return c + '/' + v + '-chromium-linux.png'; }));
|
|
const dir = '../kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression';
|
|
if (!fs.existsSync(dir)) process.exit(0);
|
|
for (const component of fs.readdirSync(dir)) {
|
|
const cdir = path.join(dir, component);
|
|
if (!fs.statSync(cdir).isDirectory()) continue;
|
|
for (const file of fs.readdirSync(cdir)) {
|
|
const rel = component + '/' + file;
|
|
if (file.endsWith('.png') && !expected.has(rel)) { console.log('Removing stale baseline:', rel); fs.unlinkSync(path.join(cdir, file)); }
|
|
}
|
|
}
|
|
"
|
|
working-directory: packages/kilo-vscode
|
|
|
|
- name: Remove stale baselines for permission-dock-dropdown tests
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs');
|
|
const specPath = 'tests/permission-dock-dropdown.spec.ts';
|
|
const expected = new Set();
|
|
if (fs.existsSync(specPath)) {
|
|
const spec = fs.readFileSync(specPath, 'utf8');
|
|
const re = /toHaveScreenshot\(\[([^\]]+)\]\)/g;
|
|
let m;
|
|
while ((m = re.exec(spec)) !== null) {
|
|
const parts = m[1].split(',').map(s => s.trim().replace(/[\"']/g, ''));
|
|
const file = parts[parts.length - 1];
|
|
if (file) expected.add(file.replace(/\.png$/, '-chromium-linux.png'));
|
|
}
|
|
}
|
|
const dir = '../kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown';
|
|
if (!fs.existsSync(dir)) process.exit(0);
|
|
for (const file of fs.readdirSync(dir)) {
|
|
if (file.endsWith('.png') && !expected.has(file)) {
|
|
console.log('Removing stale baseline:', file);
|
|
fs.unlinkSync(dir + '/' + file);
|
|
}
|
|
}
|
|
"
|
|
working-directory: packages/kilo-vscode
|
|
|
|
- name: Check for baseline changes (fork PRs)
|
|
if: needs.check-paths.outputs.is_fork == 'true'
|
|
run: |
|
|
git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/
|
|
if git diff --cached --quiet; then
|
|
echo "No visual regression detected."
|
|
else
|
|
echo "::error::Visual regression detected. Screenshot baselines have changed."
|
|
echo "::error::Since this PR is from a fork, updated screenshots cannot be committed automatically."
|
|
echo "::error::Please ask a Kilo developer for help updating the screenshots."
|
|
git diff --cached --stat
|
|
exit 1
|
|
fi
|
|
|
|
- name: Fail if baselines still changing after auto-update
|
|
if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit-vscode.outputs.is_baseline_update == 'true'
|
|
run: |
|
|
git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/
|
|
if git diff --cached --quiet; then
|
|
echo "Baselines are stable after auto-update."
|
|
else
|
|
echo "::error::Visual regression baselines changed again after a previous auto-update commit."
|
|
echo "::error::This indicates non-deterministic screenshots that would cause an infinite update loop."
|
|
echo "::error::Please investigate the flaky screenshots and add non-deterministic stories to the SKIP set."
|
|
git diff --cached --stat
|
|
exit 1
|
|
fi
|
|
|
|
- name: Commit and push new baselines (if any)
|
|
if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit-vscode.outputs.is_baseline_update != 'true'
|
|
id: commit-baselines-vscode
|
|
env:
|
|
GH_TOKEN: ${{ secrets.BOT_PAT }}
|
|
run: |
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/
|
|
if git diff --cached --quiet; then
|
|
echo "No new baselines — nothing to commit."
|
|
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
git commit -m "chore: update kilo-vscode visual regression baselines"
|
|
git lfs push --all origin
|
|
git push --no-verify
|
|
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Fail if baselines changed
|
|
if: needs.check-paths.outputs.is_fork != 'true' && steps.commit-baselines-vscode.outputs.changed == 'true'
|
|
run: |
|
|
echo "::error::Visual regression baselines changed. New baselines have been committed to the branch. Please pull and review."
|
|
exit 1
|
|
|
|
- name: Upload test results on failure
|
|
if: failure()
|
|
uses: actions/upload-artifact@v7 # kilocode_change
|
|
with:
|
|
name: visual-regression-vscode-results
|
|
path: packages/kilo-vscode/test-results/
|
|
retention-days: 7
|