From 7fa590b29f781a5ce1a579c667b2bc2a5e8a25af Mon Sep 17 00:00:00 2001 From: "junior[bot]" Date: Thu, 21 May 2026 04:12:43 +0000 Subject: [PATCH 1/6] feat(cli): scaffold .github/workflows/ci.yml in junior init Add writeGitHubWorkflow() to the init scaffolder so new Junior apps get a basic CI workflow out of the box. The workflow runs on push to main and on pull requests, installing deps, running `pnpm check` (junior check), and `pnpm build`. Closes #390 Co-Authored-By: Claude (anthropic/claude-opus-4.6) --- packages/junior/src/cli/init.ts | 30 +++++++++++++++++++ .../junior/tests/unit/cli/init-cli.test.ts | 11 +++++++ 2 files changed, 41 insertions(+) diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index 8aefbf4c..888c37a0 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -56,6 +56,35 @@ function writeVercelJson(targetDir: string): void { ); } +function writeGitHubWorkflow(targetDir: string): void { + const workflowDir = path.join(targetDir, ".github", "workflows"); + fs.mkdirSync(workflowDir, { recursive: true }); + fs.writeFileSync( + path.join(workflowDir, "ci.yml"), + `name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm check + - run: pnpm build +`, + ); +} + export async function runInit( dir: string, log: (line: string) => void = console.log, @@ -158,6 +187,7 @@ SENTRY_ORG_SLUG= writeNitroConfig(target); writeViteConfig(target); writeVercelJson(target); + writeGitHubWorkflow(target); log(`Created ${name} at ${target}`); log(""); diff --git a/packages/junior/tests/unit/cli/init-cli.test.ts b/packages/junior/tests/unit/cli/init-cli.test.ts index 40f2601a..480519d6 100644 --- a/packages/junior/tests/unit/cli/init-cli.test.ts +++ b/packages/junior/tests/unit/cli/init-cli.test.ts @@ -34,6 +34,17 @@ describe("init cli", () => { expect(fs.existsSync(path.join(target, "app", "DESCRIPTION.md"))).toBe( true, ); + expect( + fs.existsSync(path.join(target, ".github", "workflows", "ci.yml")), + ).toBe(true); + + const workflow = fs.readFileSync( + path.join(target, ".github", "workflows", "ci.yml"), + "utf8", + ); + expect(workflow).toContain("pnpm check"); + expect(workflow).toContain("pnpm build"); + expect(workflow).toContain("pnpm install --frozen-lockfile"); const vercelConfig = JSON.parse( fs.readFileSync(path.join(target, "vercel.json"), "utf8"), From f4c1c367b15cce11c053b8ecca7e9e4df9cd12f1 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 04:18:12 +0000 Subject: [PATCH 2/6] fix: use node 24 (active LTS) in scaffolded CI workflow Co-Authored-By: Claude (anthropic/claude-opus-4.6) --- packages/junior/src/cli/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index 888c37a0..bbb907ce 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -76,7 +76,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version: 22 + node-version: 24 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm check From fb6a8cfb3f782e1f044c9e8ede6d92b5ac7fff5d Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 04:19:40 +0000 Subject: [PATCH 3/6] chore: bump scaffolded CI actions to v6 actions/checkout@v6, actions/setup-node@v6, pnpm/action-setup@v6 Co-Authored-By: Claude (anthropic/claude-opus-4.6) --- packages/junior/src/cli/init.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index bbb907ce..b6c163cb 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -72,9 +72,9 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v6 with: node-version: 24 cache: pnpm From 284c0e8b26e81050116b47b23befa0ca07b2edaa Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 04:24:05 +0000 Subject: [PATCH 4/6] fix: add packageManager pnpm@10 to scaffolded package.json pnpm/action-setup requires either a version input or a packageManager field in package.json. Without it, CI fails on first run. Co-Authored-By: Claude (anthropic/claude-opus-4.6) --- packages/junior/src/cli/init.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index b6c163cb..aa27cf56 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -113,6 +113,7 @@ export async function runInit( version: "0.1.0", private: true, type: "module", + packageManager: "pnpm@10", scripts: { dev: "vite dev", check: "junior check", From e28b331822ba9831335f621c2e00eb9f7cf6ccaf Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 04:31:34 +0000 Subject: [PATCH 5/6] fix: use valid semver for packageManager field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit corepack rejects bare major versions like 'pnpm@10' — it requires exact semver. Use 'pnpm@10.0.0' as the scaffold baseline; users can run 'corepack use pnpm@latest' to update. Add regression test asserting packageManager matches exact semver. Co-Authored-By: Claude (anthropic/claude-opus-4.6) --- packages/junior/src/cli/init.ts | 2 +- packages/junior/tests/unit/cli/init-cli.test.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index aa27cf56..8e7c4098 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -113,7 +113,7 @@ export async function runInit( version: "0.1.0", private: true, type: "module", - packageManager: "pnpm@10", + packageManager: "pnpm@10.0.0", scripts: { dev: "vite dev", check: "junior check", diff --git a/packages/junior/tests/unit/cli/init-cli.test.ts b/packages/junior/tests/unit/cli/init-cli.test.ts index 480519d6..949f1d0f 100644 --- a/packages/junior/tests/unit/cli/init-cli.test.ts +++ b/packages/junior/tests/unit/cli/init-cli.test.ts @@ -62,6 +62,7 @@ describe("init cli", () => { expect(pkg.scripts.dev).toBe("vite dev"); expect(pkg.scripts.check).toBe("junior check"); expect(pkg.scripts.build).toBe("junior snapshot create && vite build"); + expect(pkg.packageManager).toMatch(/^pnpm@\d+\.\d+\.\d+$/); }); it("refuses to initialize a non-empty directory", async () => { From 1ff357af0646feb1a44866cb23c70c318967e355 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 04:34:34 +0000 Subject: [PATCH 6/6] ref: drop packageManager, use pnpm/action-setup version input instead Scaffolded projects don't actively maintain a packageManager pin, so it goes stale immediately. Instead, let pnpm/action-setup resolve the latest pnpm 10.x via its version input. Users who want corepack pinning can add packageManager themselves when ready. Co-Authored-By: Claude (anthropic/claude-opus-4.6) --- packages/junior/src/cli/init.ts | 3 ++- packages/junior/tests/unit/cli/init-cli.test.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index 8e7c4098..cd11cd20 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -74,6 +74,8 @@ jobs: steps: - uses: actions/checkout@v6 - uses: pnpm/action-setup@v6 + with: + version: 10 - uses: actions/setup-node@v6 with: node-version: 24 @@ -113,7 +115,6 @@ export async function runInit( version: "0.1.0", private: true, type: "module", - packageManager: "pnpm@10.0.0", scripts: { dev: "vite dev", check: "junior check", diff --git a/packages/junior/tests/unit/cli/init-cli.test.ts b/packages/junior/tests/unit/cli/init-cli.test.ts index 949f1d0f..480519d6 100644 --- a/packages/junior/tests/unit/cli/init-cli.test.ts +++ b/packages/junior/tests/unit/cli/init-cli.test.ts @@ -62,7 +62,6 @@ describe("init cli", () => { expect(pkg.scripts.dev).toBe("vite dev"); expect(pkg.scripts.check).toBe("junior check"); expect(pkg.scripts.build).toBe("junior snapshot create && vite build"); - expect(pkg.packageManager).toMatch(/^pnpm@\d+\.\d+\.\d+$/); }); it("refuses to initialize a non-empty directory", async () => {