Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
30 changes: 18 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,41 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
- uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Pull environment variables from Vercel
run: npx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} --yes
run: pnpm dlx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} --yes
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all unpinned Vercel dlx usages in workflows
rg -nP 'pnpm dlx vercel(?!@)' .github/workflows

Repository: dejanvasic85/williamstownsc

Length of output: 309


Pin vercel in pnpm dlx for deterministic CI runs.

Unpinned dlx commands download the latest available version at execution time, which can vary across runs and compromise CI reproducibility. Use pnpm dlx vercel@<pinned-version> instead.

Suggested update
- run: pnpm dlx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} --yes
+ run: pnpm dlx vercel@<pinned-version> env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} --yes

Also applies to: 53-53

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml at line 27, Change the unpinned pnpm dlx invocation
that runs "pnpm dlx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN
}} --yes" to a pinned vercel release, e.g. "pnpm dlx vercel@<version> env pull
.env.local --token=${{ secrets.VERCEL_TOKEN }} --yes", and apply the same change
to the other identical dlx invocation (the second occurrence of the pnpm dlx
vercel command) so CI uses a deterministic vercel version.

- name: Build
run: npm run build
run: pnpm run build
- name: Lint
run: npm run lint
run: pnpm run lint
- name: Type check
run: npm run type:check
run: pnpm run type:check
- name: Format
run: npm run format:check
run: pnpm run format:check

e2e:
name: E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 20
needs: test
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
- uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
run: pnpm exec playwright install --with-deps chromium
- name: Pull environment variables from Vercel
run: npx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} --yes
run: pnpm dlx vercel env pull .env.local --token=${{ secrets.VERCEL_TOKEN }} --yes
- name: Wait for Vercel preview deployment
uses: patrickedqvist/[email protected]
id: wait_for_vercel
Expand All @@ -53,7 +59,7 @@ jobs:
max_timeout: 300
check_interval: 10
- name: Run E2E tests
run: npm run test:e2e
run: pnpm run test:e2e
env:
PLAYWRIGHT_TEST_BASE_URL: ${{ steps.wait_for_vercel.outputs.url }}
- name: Upload test results
Expand Down
42 changes: 27 additions & 15 deletions .github/workflows/crawl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
- uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- id: chunk
name: Compute chunks
run: |
SIZE=${{ github.event.inputs.chunk_size || '4' }}
echo "chunks=$(npx tsx bin/wsc.ts list chunks --size $SIZE)" >> $GITHUB_OUTPUT
echo "chunks=$(pnpm exec tsx bin/wsc.ts list chunks --size $SIZE)" >> $GITHUB_OUTPUT

crawl-clubs:
name: Crawl clubs
Expand All @@ -44,19 +47,22 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
- uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-chrome-${{ hashFiles('package-lock.json') }}
key: playwright-chrome-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install Chrome
run: npx playwright install --with-deps chrome
run: pnpm exec playwright install --with-deps chrome
- name: Crawl clubs
run: npm run crawl:clubs:ci
run: pnpm run crawl:clubs:ci
- name: Sync clubs
run: npm run sync:clubs
run: pnpm run sync:clubs
- uses: actions/upload-artifact@v4
with:
name: clubs-data
Expand All @@ -74,25 +80,28 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
- uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-chrome-${{ hashFiles('package-lock.json') }}
key: playwright-chrome-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install Chrome
run: npx playwright install --with-deps chrome
run: pnpm exec playwright install --with-deps chrome

- name: Crawl fixtures for chunk
run: xvfb-run --auto-servernum npx tsx bin/wsc.ts crawl fixtures --team ${{ join(matrix.chunk, ' --team ') }}
run: xvfb-run --auto-servernum pnpm exec tsx bin/wsc.ts crawl fixtures --team ${{ join(matrix.chunk, ' --team ') }}

- name: Sync fixtures and tables for chunk
run: |
mkdir -p tmp/crawl/matches tmp/crawl/table
for team in ${{ join(matrix.chunk, ' ') }}; do
npx tsx bin/wsc.ts sync fixtures --team "$team"
npx tsx bin/wsc.ts sync table --team "$team"
pnpm exec tsx bin/wsc.ts sync fixtures --team "$team"
pnpm exec tsx bin/wsc.ts sync table --team "$team"
if [[ -f "data/matches/$team.json" ]]; then
cp "data/matches/$team.json" "tmp/crawl/matches/$team.json"
else
Expand Down Expand Up @@ -125,8 +134,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
- uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- uses: actions/download-artifact@v4
with:
pattern: clubs-data
Expand All @@ -144,7 +156,7 @@ jobs:
path: data/table/
merge-multiple: true
- name: Format code
run: npm run format
run: pnpm run format
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v8
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/deploy-sanity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v4

- uses: jdx/mise-action@v4

- uses: pnpm/action-setup@v4
with:
version: 10.5.2
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actions/checkout is pinned to v6 here, while other workflows in the repo use actions/checkout@v4 (e.g. crawl.yml). Consider aligning the major version across workflows to reduce the chance of workflow drift and hard-to-debug CI differences.

Copilot uses AI. Check for mistakes.

- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile

- name: Deploy to Sanity
run: npm run deploy:sanity -- --yes
run: pnpm run deploy:sanity -- --yes
env:
SANITY_AUTH_TOKEN: ${{ secrets.SANITY_AUTH_TOKEN }}
NEXT_PUBLIC_SANITY_PROJECT_ID: ${{ vars.SANITY_PROJECT_ID }}
Expand Down
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ node_modules

# Ignore files for PNPM, NPM and YARN
package-lock.json
pnpm-lock.yaml
yarn.lock

# Nextjs
.next
Expand Down
34 changes: 17 additions & 17 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
# Environment & Commands

- **IMPORTANT**: Dev server runs on port 3003 (not 3000): `npm run dev`
- Node version: 24.12.0 (managed by Volta)
- **IMPORTANT**: Dev server runs on port 3003 (not 3000): `pnpm run dev`
- Node version: 24.12.0 (managed by Mise)
- TypeScript path aliases: `@/*` (src), `@data/*` (data)
- Required env vars: see .env.example (Sanity, AWS SES, reCAPTCHA)
- Sanity Studio: separate at /studio path

## Key Commands (see package.json for full list)

- `npm run dev` - Dev server on port 3003
- `npm run test:e2e[:ui|:debug|:report]` - Playwright E2E tests
- `npm run crawl:[clubs|fixtures]` - Playwright-based web scraping
- `npm run sync:[clubs|fixtures]` - Sync scraped data to Sanity
- `npm run type:gen` - Regenerate Sanity types after schema changes
- `pnpm run dev` - Dev server on port 3003
- `pnpm run test:e2e[:ui|:debug|:report]` - Playwright E2E tests
- `pnpm run crawl:[clubs|fixtures]` - Playwright-based web scraping
- `pnpm run sync:[clubs|fixtures]` - Sync scraped data to Sanity
- `pnpm run type:gen` - Regenerate Sanity types after schema changes

# Testing

- Framework: Playwright only (no unit test framework)
- Tests run against http://localhost:3003
- Run E2E tests: `npm run test:e2e`
- Run with UI mode: `npm run test:e2e:ui`
- Debug mode: `npm run test:e2e:debug`
- View report: `npm run test:e2e:report`
- Run E2E tests: `pnpm run test:e2e`
- Run with UI mode: `pnpm run test:e2e:ui`
- Debug mode: `pnpm run test:e2e:debug`
- View report: `pnpm run test:e2e:report`

# Technical Requirements

Expand Down Expand Up @@ -62,11 +62,11 @@
All changes MUST follow the following workflow

- After finishing code changes and **before every push**, run all checks in order:
1. `npm run format`
2. `npm run lint`
3. `npm run type:check`
4. `npm run build`
5. `npm run test:e2e`
1. `pnpm run format`
2. `pnpm run lint`
3. `pnpm run type:check`
4. `pnpm run build`
5. `pnpm run test:e2e`
- Never push without running these checks — commit any formatting changes before pushing
- Pre-commit hooks auto-run: Husky runs lint-staged (prettier + eslint)
- Update any plan files with progress to help with issue tracking
Expand Down Expand Up @@ -96,5 +96,5 @@ All changes MUST follow the following workflow
- **NEVER**: create "helpers" or "utils" (use services/mappers/transformers)
- Playwright-based web scraping: crawl scripts use playwright-core for data extraction
- Pre-commit hooks auto-run: changes will trigger prettier + eslint
- Run `npm run type:gen` after Sanity schema changes
- Run `pnpm run type:gen` after Sanity schema changes
- Prettier line width: 100 chars (not default 80)
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,22 @@ To run the site locally, follow these steps:

### Prerequisites

- Node.js 24 installed
- Node.js 24.12.0 installed (managed by Mise)
- pnpm 10.5.2 installed
- A Sanity account and project set up

### CLI tools

The data CLI uses Playwright. Before running crawl commands, install the browser binaries:

```bash
npx playwright install --with-deps chromium
pnpm exec playwright install --with-deps chromium
```

### Install dependencies

```bash
pnpm install
```

## Content Management
Expand All @@ -74,7 +81,7 @@ Sanity URLs:
After modifying Sanity schemas in `src/sanity/schema/`, run:

```bash
npm run type:gen
pnpm run type:gen
```

This will update the TypeScript types to match your schema changes.
Expand Down
48 changes: 48 additions & 0 deletions docs/plans/2026-04-28-pnpm-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Migrate repo to pnpm

**Created:** 2026-04-28
**Status:** In Progress

## Purpose

Standardize project package manager on pnpm. Keep local docs and GitHub workflows aligned to prevent drift and CI failures.

## Requirements

- Use pnpm as canonical package manager for local and CI workflows
- Remove npm lockfile and commit pnpm lockfile
- Update script references in active docs and workflow docs
- Update GitHub Actions install and command steps to pnpm

## Todo

- [x] Generate `pnpm-lock.yaml` from current dependency graph
- [x] Add `packageManager` in `package.json`
- [x] Update build script chaining in `package.json` to pnpm
- [x] Configure `pnpm.onlyBuiltDependencies` for known postinstall/build-script deps
- [x] Remove `package-lock.json`
- [x] Migrate `.github/workflows/ci.yml` to pnpm install/exec/run commands
- [x] Migrate `.github/workflows/crawl.yml` to pnpm install/exec/run commands and lockfile cache key
- [x] Migrate `.github/workflows/deploy-sanity.yml` to pnpm install/run commands
- [x] Update command docs in `README.md`
- [x] Update command docs in `AGENTS.md`
- [x] Run `pnpm run type:check`
- [x] Run `pnpm run lint`
- [x] Run `pnpm run format`
- [x] Run `pnpm run build`
- [ ] Run `pnpm run test:e2e` (1 failing test: `tests/search.spec.ts` navigation assertion)

## Files

- `package.json`: set pnpm package manager, update build chaining, add pnpm build-script allowlist
- `pnpm-lock.yaml`: new lockfile generated via pnpm install
- `package-lock.json`: removed
- `.github/workflows/ci.yml`: npm/npx commands replaced with pnpm equivalents
- `.github/workflows/crawl.yml`: npm/npx commands replaced with pnpm equivalents, cache key now uses pnpm lockfile
- `.github/workflows/deploy-sanity.yml`: npm commands replaced with pnpm equivalents
- `README.md`: local setup and schema typegen commands updated to pnpm
- `AGENTS.md`: workflow command references updated to pnpm

## Unresolved questions

- None
34 changes: 34 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,44 @@ import nextTs from 'eslint-config-next/typescript';
import prettier from 'eslint-config-prettier/flat';
import { defineConfig, globalIgnores } from 'eslint/config';

const dependencyCheckConfigValue = {
files: ['**/*.{js,mjs,cjs,jsx,ts,tsx}'],
settings: {
'import/internal-regex': '^(@/|@data/)',
'import/resolver': {
typescript: {
project: './tsconfig.json'
}
}
},
rules: {
'import/no-extraneous-dependencies': [
'error',
Comment on lines +16 to +18
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import/no-extraneous-dependencies is configured, but the flat config doesn’t register eslint-plugin-import under plugins. With the current file, ESLint will fail with “Definition for rule 'import/no-extraneous-dependencies' was not found” unless another config happens to register it. Import eslint-plugin-import and add it to this config object’s plugins map (e.g., plugins: { import: importPlugin }) before using import/* rules.

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +18
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import/no-extraneous-dependencies is configured, but the flat config does not register eslint-plugin-import under plugins. Without that, ESLint will fail with an unknown rule. Import eslint-plugin-import and add plugins: { import: importPlugin } (and keep the existing settings/rules).

Copilot uses AI. Check for mistakes.
{
packageDir: ['.'],
devDependencies: [
'bin/**/*.{js,mjs,cjs,ts,tsx}',
'**/*.test.{js,jsx,ts,tsx}',
'**/*.spec.{js,jsx,ts,tsx}',
'**/tests/**/*.{js,jsx,ts,tsx}',
'playwright.config.ts',
'eslint.config.mjs',
'next.config.ts',
'sanity.config.ts',
'sanity.cli.ts'
],
optionalDependencies: false,
peerDependencies: false
}
]
}
};

const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
prettier,
dependencyCheckConfigValue,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
Expand Down
Loading
Loading