diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d2e2e49..71d282e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,6 +3,15 @@ name: Publish to npm on: release: types: [published] + # Called directly by release.yml after it cuts the tag/release. A reusable + # workflow_call is a direct invocation, so it runs even though the release + # was created with GITHUB_TOKEN (whose events don't trigger other workflows). + workflow_call: + inputs: + dry-run: + description: 'Dry run (skip actual publish)' + type: boolean + default: false workflow_dispatch: inputs: dry-run: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a66c276..ec94615 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,9 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + outputs: + changed: ${{ steps.version.outputs.changed }} + version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v4 with: @@ -41,3 +44,13 @@ jobs: gh release create "$TAG" \ --title "$TAG" \ --generate-notes + + # Publish straight after the release is cut. Called as a reusable workflow + # (not via the `release: published` event, which GITHUB_TOKEN-created releases + # never fire) so a version bump on main now auto-publishes to npm with no + # manual dispatch and no PAT. Skipped when the version didn't change. + publish: + needs: release + if: needs.release.outputs.changed == 'true' + uses: ./.github/workflows/publish.yml + secrets: inherit diff --git a/src/plugin/__tests__/transform-react.test.ts b/src/plugin/__tests__/transform-react.test.ts index b9b9000..93531a7 100644 --- a/src/plugin/__tests__/transform-react.test.ts +++ b/src/plugin/__tests__/transform-react.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { globSync, readFileSync } from 'node:fs' +import { readdirSync, readFileSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import ts from 'typescript' @@ -354,7 +354,12 @@ describe('transformJSX', () => { path.dirname(fileURLToPath(import.meta.url)), '../../../playgrounds/simple/react-vite' ) - const files = globSync('src/**/*.{tsx,jsx}', { cwd: playgroundRoot }) + // Recursive readdir (Node 18.17+/20) — NOT fs.globSync, which is Node 22+ + // and would throw on CI's Node 20. + const files = readdirSync(path.join(playgroundRoot, 'src'), { recursive: true }) + .map(String) + .filter((f) => f.endsWith('.tsx') || f.endsWith('.jsx')) + .map((f) => path.join('src', f)) expect(files.length).toBeGreaterThan(0) for (const rel of files) { const file = path.join(playgroundRoot, rel) diff --git a/src/plugin/__tests__/transform-svelte.test.ts b/src/plugin/__tests__/transform-svelte.test.ts index 0e12d4c..24a3ee2 100644 --- a/src/plugin/__tests__/transform-svelte.test.ts +++ b/src/plugin/__tests__/transform-svelte.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { globSync, readFileSync } from 'node:fs' +import { readdirSync, readFileSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import { compile } from 'svelte/compiler' @@ -287,7 +287,12 @@ describe('transformSvelte', () => { path.dirname(fileURLToPath(import.meta.url)), '../../../playgrounds/simple/svelte-vite' ) - const files = globSync('src/**/*.svelte', { cwd: playgroundRoot }) + // Recursive readdir (Node 18.17+/20) — NOT fs.globSync, which is Node 22+ + // and would throw on CI's Node 20. + const files = readdirSync(path.join(playgroundRoot, 'src'), { recursive: true }) + .map(String) + .filter((f) => f.endsWith('.svelte')) + .map((f) => path.join('src', f)) expect(files.length).toBeGreaterThan(0) for (const rel of files) { const file = path.join(playgroundRoot, rel)