Skip to content

Let users choose new vs. same chat when switching to plan mode #6958

Let users choose new vs. same chat when switching to plan mode

Let users choose new vs. same chat when switching to plan mode #6958

Workflow file for this run

name: CI
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, closed]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
check-changes:
# Skip closed PR events (we only listen to 'closed' to trigger cancellation of in-progress runs)
if: github.event.action != 'closed'
runs-on: ubuntu-latest
outputs:
should_run_tests: ${{ steps.check.outputs.should_run_tests }}
should_run_schema_diff_tests: ${{ steps.check.outputs.should_run_schema_diff_tests }}
should_run_schema_classifier_tests: ${{ steps.check.outputs.should_run_schema_classifier_tests }}
build_os: ${{ steps.matrix.outputs.build_os }}
e2e_os: ${{ steps.matrix.outputs.e2e_os }}
e2e_shard: ${{ steps.matrix.outputs.e2e_shard }}
e2e_shard_total: ${{ steps.matrix.outputs.e2e_shard_total }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || '' }}
fetch-depth: 0
- name: Check changed files
id: check
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
else
# For push events, compare with parent commit
BASE_SHA="${{ github.event.before }}"
HEAD_SHA="${{ github.sha }}"
fi
# Get list of changed files
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" 2>/dev/null || echo "")
if [ -z "$CHANGED_FILES" ]; then
echo "should_run_tests=true" >> $GITHUB_OUTPUT
echo "should_run_schema_diff_tests=false" >> $GITHUB_OUTPUT
echo "should_run_schema_classifier_tests=false" >> $GITHUB_OUTPUT
echo "Running tests: could not determine changed files"
echo "Skipping ts-pg-schema-diff tests: could not determine changed files"
echo "Skipping pg-schema-classifier tests: could not determine changed files"
exit 0
fi
echo "Changed files:"
echo "$CHANGED_FILES"
if echo "$CHANGED_FILES" | grep -q "^packages/ts-pg-schema-diff/"; then
echo "should_run_schema_diff_tests=true" >> $GITHUB_OUTPUT
echo "Running ts-pg-schema-diff tests: package files changed"
else
echo "should_run_schema_diff_tests=false" >> $GITHUB_OUTPUT
echo "Skipping ts-pg-schema-diff tests: no package files changed"
fi
if echo "$CHANGED_FILES" | grep -q "^packages/pg-schema-classifier/"; then
echo "should_run_schema_classifier_tests=true" >> $GITHUB_OUTPUT
echo "Running pg-schema-classifier tests: package files changed"
else
echo "should_run_schema_classifier_tests=false" >> $GITHUB_OUTPUT
echo "Skipping pg-schema-classifier tests: no package files changed"
fi
if [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref }}" = "refs/heads/main" ]; then
# Always run app tests on pushes to main.
echo "should_run_tests=true" >> $GITHUB_OUTPUT
echo "Running tests: push to main branch"
exit 0
fi
# Check if all changed files are in config-only directories (.claude, rules)
NON_CONFIG_FILES=$(echo "$CHANGED_FILES" | grep -v "^\.claude/" | grep -v "^rules/" || true)
if [ -z "$NON_CONFIG_FILES" ]; then
echo "should_run_tests=false" >> $GITHUB_OUTPUT
echo "Skipping tests: all changed files are in .claude/ or rules/"
else
echo "should_run_tests=true" >> $GITHUB_OUTPUT
echo "Running tests: found files outside .claude/ and rules/:"
echo "$NON_CONFIG_FILES"
fi
- name: Detect privileged author
id: author-check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
AUTHOR=""
if [ "${{ github.event_name }}" = "pull_request" ]; then
AUTHOR="${{ github.event.pull_request.user.login }}"
fi
echo "Author: $AUTHOR"
# Lowercase before matching so a login like "RyanGroch" matches the
# same lowercased allowlist used by the AI-review workflows.
AUTHOR_LC="${AUTHOR,,}"
case "$AUTHOR_LC" in
wwwillchen|keppo-bot|keppo-bot\[bot\]|dyad-assistant|azizmejri1|ryangroch)
echo "is_privileged=true" >> $GITHUB_OUTPUT
;;
*)
echo "is_privileged=false" >> $GITHUB_OUTPUT
;;
esac
# Sets the dynamic matrix for the build and e2e-tests jobs based on the PR author.
# The "image" field is a JSON-encoded array string so that fromJSON() in runs-on
# can produce the correct label(s) for both GitHub-hosted and self-hosted runners.
#
# Privileged authors (wwwillchen, keppo-bot/keppo-bot[bot], dyad-assistant, azizmejri1, ryangroch):
# - Self-hosted macOS ARM64 runners, no Windows, 4 shards.
#
# build (macOS self-hosted) ──> e2e-tests (macOS self-hosted, shards 1-4) ──> merge-reports
#
# All other authors:
# - GitHub-hosted runners for macOS + Windows, 4 shards each.
#
# build (macOS) ──┐
# build (Windows) ┼──> e2e-tests (macOS shards 1-4) ──┐
# │ e2e-tests (Windows shards 1-4) ──┼──> merge-reports
# └──────────────────────────────────────┘
- name: Set CI matrix
id: matrix
run: |
if [ "${{ steps.author-check.outputs.is_privileged }}" = "true" ]; then
echo 'build_os=[{"name":"macos","image":"[\"self-hosted\",\"macOS\",\"ARM64\"]"}]' >> $GITHUB_OUTPUT
echo 'e2e_os=[{"name":"macos","image":"[\"self-hosted\",\"macOS\",\"ARM64\"]"}]' >> $GITHUB_OUTPUT
echo 'e2e_shard=[1,2,3,4]' >> $GITHUB_OUTPUT
echo 'e2e_shard_total=[4]' >> $GITHUB_OUTPUT
else
echo 'build_os=[{"name":"windows","image":"[\"windows-latest\"]"},{"name":"macos","image":"[\"macos-latest\"]"}]' >> $GITHUB_OUTPUT
echo 'e2e_os=[{"name":"windows","image":"[\"windows-latest\"]"},{"name":"macos","image":"[\"macos-latest\"]"}]' >> $GITHUB_OUTPUT
echo 'e2e_shard=[1,2,3,4]' >> $GITHUB_OUTPUT
echo 'e2e_shard_total=[4]' >> $GITHUB_OUTPUT
fi
ts-pg-schema-diff-tests:
needs: [check-changes]
if: needs.check-changes.outputs.should_run_schema_diff_tests == 'true'
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || '' }}
- name: Initialize environment
uses: actions/setup-node@v5
with:
node-version: v24.13.1
cache: npm
cache-dependency-path: package-lock.json
- name: Install npm 11.8.0
run: npm install -g npm@11.8.0
- name: Install PostgreSQL
run: |
sudo apt-get update
sudo apt-get install -y postgresql-client
pg_dump --version
- name: Install node modules
run: bash scripts/npm-ci-retry.sh
env:
# Required for @vscode/ripgrep to download binaries without hitting GitHub API rate limits
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Type-check ts-pg-schema-diff
run: npm --prefix packages/ts-pg-schema-diff run typecheck
- name: Unit tests
run: npm --prefix packages/ts-pg-schema-diff test
- name: Integration tests
run: npm --prefix packages/ts-pg-schema-diff run test:integration
env:
PG_SCHEMA_DIFF_TEST_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres
pg-schema-classifier-tests:
needs: [check-changes]
if: needs.check-changes.outputs.should_run_schema_classifier_tests == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || '' }}
- name: Initialize environment
uses: actions/setup-node@v5
with:
node-version: v24.13.1
cache: npm
cache-dependency-path: package-lock.json
- name: Install npm 11.8.0
run: npm install -g npm@11.8.0
- name: Install node modules
run: bash scripts/npm-ci-retry.sh
env:
# Required for @vscode/ripgrep to download binaries without hitting GitHub API rate limits
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Type-check pg-schema-classifier
run: npm --prefix packages/pg-schema-classifier run typecheck
- name: Unit tests
run: npm --prefix packages/pg-schema-classifier test
build:
needs: [check-changes]
if: needs.check-changes.outputs.should_run_tests == 'true'
# Why Mac and Windows?
# I can't run electron playwright on ubuntu-latest and
# Linux support for Dyad is experimental so not as important
# as Mac + Windows
strategy:
fail-fast: false
matrix:
os: ${{ fromJSON(needs.check-changes.outputs.build_os) }}
runs-on: ${{ fromJSON(matrix.os.image) }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || '' }}
- name: Initialize environment
uses: actions/setup-node@v5
with:
node-version: v24.13.1
cache: npm
cache-dependency-path: package-lock.json
- name: Install npm 11.8.0
run: npm install -g npm@11.8.0
- name: Install node modules
run: bash scripts/npm-ci-retry.sh
env:
# Required for @vscode/ripgrep to download binaries without hitting GitHub API rate limits
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Presubmit check (e.g. lint, format)
# do not run this on Windows (it fails and not necessary)
if: contains(matrix.os.name, 'macos')
run: npm run presubmit
- name: Type-checking
# do not run this on windows (it's redundant)
if: contains(matrix.os.name, 'macos')
run: npm run ts
- name: Unit tests
# do not run this on windows (it's redundant)
if: contains(matrix.os.name, 'macos')
run: npm run test
- name: Build
env:
NODE_OPTIONS: "--max-old-space-size=4096"
run: npm run pre:e2e
- name: Prep test server
run: cd testing/fake-llm-server && npm install && npm run build && cd -
# macOS: Archive app bundle with tar to preserve metadata (code signatures, extended attributes)
# This is necessary because GitHub artifact upload/download loses these attributes
- name: Archive macOS app bundle
if: contains(matrix.os.name, 'macos')
run: tar -cvf out-macos.tar out/
- name: Upload build artifacts (macOS)
if: contains(matrix.os.name, 'macos')
uses: actions/upload-artifact@v6
with:
name: build-${{ matrix.os.name }}
path: |
out-macos.tar
scaffold/
testing/fake-llm-server/
retention-days: 1
- name: Upload build artifacts (Windows)
if: contains(matrix.os.name, 'windows')
uses: actions/upload-artifact@v6
with:
name: build-${{ matrix.os.name }}
path: |
out/
scaffold/
testing/fake-llm-server/
retention-days: 1
- name: Cleanup (self-hosted macOS)
if: always() && contains(matrix.os.image, 'self-hosted')
run: bash scripts/ci-cleanup-macos.sh
e2e-tests:
needs: [check-changes, build]
strategy:
fail-fast: false
matrix:
os: ${{ fromJSON(needs.check-changes.outputs.e2e_os) }}
shard: ${{ fromJSON(needs.check-changes.outputs.e2e_shard) }}
shardTotal: ${{ fromJSON(needs.check-changes.outputs.e2e_shard_total) }}
runs-on: ${{ fromJSON(matrix.os.image) }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || '' }}
- name: Initialize environment
uses: actions/setup-node@v5
with:
node-version: v24.13.1
cache: npm
cache-dependency-path: package-lock.json
- name: Install npm 11.8.0
run: npm install -g npm@11.8.0
- name: Install node modules
run: bash scripts/npm-ci-retry.sh
env:
# Required for @vscode/ripgrep to download binaries without hitting GitHub API rate limits
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
with:
version: 10.33.2
- name: Clone nextjs-template
run: git clone --depth 1 https://github.com/dyad-sh/nextjs-template.git nextjs-template
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ matrix.os.name }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ matrix.os.name }}-pnpm-store-
# Not strictly needed but makes the e2e tests faster (and less flaky)
- name: Install scaffold dependencies
run: cd scaffold && pnpm install
- name: Install nextjs-template dependencies
run: cd nextjs-template && pnpm install
- name: Download build artifacts
uses: actions/download-artifact@v7
with:
name: build-${{ matrix.os.name }}
# macOS: Extract tar archive to restore app bundle with preserved metadata
- name: Extract macOS app bundle
if: contains(matrix.os.name, 'macos')
run: tar -xvf out-macos.tar
- name: Install Chromium browser for Playwright
run: npx playwright install chromium --with-deps
- name: E2E tests (Shard ${{ matrix.shard }}/${{ matrix.shardTotal }})
env:
FLAKINESS_ACCESS_TOKEN: ${{ secrets.FLAKINESS_ACCESS_TOKEN }}
# Self-hosted macOS runners use fewer retries (1) vs GitHub-hosted CI (2)
PLAYWRIGHT_RETRIES: ${{ contains(matrix.os.image, 'self-hosted') && '1' || '2' }}
# You can add debug logging to make it easier to see what's failing
# by adding "DEBUG=pw:browser" in front.
# Use blob reporter for sharding and merge capabilities
run: DEBUG=pw:browser npx playwright test --shard=${{ matrix.shard }}/${{ matrix.shardTotal }}
- name: Record shard metadata
if: ${{ !cancelled() }}
run: |
mkdir -p blob-report
cat <<EOF > "blob-report/_playwright-shard-metadata-${{ matrix.os.name }}-shard-${{ matrix.shard }}-of-${{ matrix.shardTotal }}.json"
{
"os": "${{ matrix.os.name }}",
"shard": ${{ matrix.shard }},
"total": ${{ matrix.shardTotal }}
}
EOF
- name: Upload shard results
uses: actions/upload-artifact@v6
if: ${{ !cancelled() }}
with:
name: blob-report-${{ matrix.os.name }}-shard-${{ matrix.shard }}
path: blob-report
retention-days: 1
- name: Upload flakiness report (for fork PRs)
uses: actions/upload-artifact@v6
if: ${{ !cancelled() }}
with:
name: flakiness-report-${{ matrix.os.name }}-shard-${{ matrix.shard }}
path: flakiness-report
retention-days: 1
- name: Cleanup (self-hosted macOS)
if: always() && contains(matrix.os.image, 'self-hosted')
run: bash scripts/ci-cleanup-macos.sh
merge-reports:
# Merge reports after playwright-tests, even if some shards have failed
# Skip if tests were skipped (only .claude files changed)
if: ${{ !cancelled() && needs.check-changes.outputs.should_run_tests == 'true' }}
needs: [check-changes, e2e-tests]
permissions:
contents: read
pull-requests: write
actions: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || '' }}
- uses: actions/setup-node@v5
with:
node-version: v24.13.1
- name: Install npm 11.8.0
run: npm install -g npm@11.8.0
- name: Install dependencies
run: npm ci --no-audit --no-fund --progress=false
env:
# Required for @vscode/ripgrep to download binaries without hitting GitHub API rate limits
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v7
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Debug - List downloaded blob reports
run: |
echo "Contents of all-blob-reports directory:"
ls -la all-blob-reports/
echo "File sizes and details:"
find all-blob-reports/ -type f -exec ls -lh {} \; || echo "No files found"
- name: Merge into HTML Report
run: PLAYWRIGHT_HTML_OUTPUT_DIR=playwright-report npx playwright merge-reports --config=merge.config.ts ./all-blob-reports
- name: Debug - List playwright-report contents
run: |
echo "Contents of playwright-report directory:"
ls -la playwright-report/ || echo "playwright-report directory does not exist"
echo "Current directory contents:"
ls -la
- name: Upload HTML report
uses: actions/upload-artifact@v6
with:
name: html-report
path: playwright-report
retention-days: 3
overwrite: true
- name: Generate Playwright summary
uses: actions/github-script@v8
env:
PLAYWRIGHT_RUN_ID: ${{ github.run_id }}
with:
script: |
const { run } = require('./scripts/generate-playwright-summary.js');
await run({ github, context, core });