diff --git a/.github/scripts/has-unpublished-packages.mjs b/.github/scripts/has-unpublished-packages.mjs new file mode 100644 index 00000000..4126c425 --- /dev/null +++ b/.github/scripts/has-unpublished-packages.mjs @@ -0,0 +1,54 @@ +import { appendFileSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; + +async function hasPublishedVersion(pkg) { + const response = await fetch( + `https://registry.npmjs.org/${encodeURIComponent(pkg.name)}`, + { headers: { accept: 'application/vnd.npm.install-v1+json' } } + ); + + if (response.status === 404) { + return false; + } + + if (!response.ok) { + throw new Error( + `Failed to query ${pkg.name}: ${response.status} ${response.statusText}` + ); + } + + const metadata = await response.json(); + return Object.prototype.hasOwnProperty.call( + metadata.versions ?? {}, + pkg.version + ); +} + +async function main() { + const pkg = JSON.parse(await readFile('package.json', 'utf8')); + const isPublished = await hasPublishedVersion(pkg); + + if (isPublished) { + console.log(`${pkg.name}@${pkg.version} is already published`); + } else { + console.log(`${pkg.name}@${pkg.version} is not published yet`); + } + + const shouldPublish = !isPublished; + const output = + [ + `has_unpublished=${String(shouldPublish)}`, + `should_publish=${String(shouldPublish)}` + ].join('\n') + '\n'; + + if (process.env.GITHUB_OUTPUT) { + appendFileSync(process.env.GITHUB_OUTPUT, output); + } else { + process.stdout.write(output); + } +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c19aa95d..027ede0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: cache: npm - name: Update npm - run: npm install -g npm@latest + run: npm install -g npm@11.11.1 - run: npm ci - name: test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 31a42a1f..b2189638 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,38 +5,89 @@ on: branches: - main +concurrency: ${{ github.workflow }}-${{ github.ref }} + jobs: release: name: Release - runs-on: ubuntu-latest + outputs: + has_changesets: ${{ steps.changesets.outputs.hasChangesets }} + should_publish: ${{ steps.publish-check.outputs.should_publish }} permissions: contents: write - id-token: write issues: read pull-requests: write + runs-on: ubuntu-latest steps: - - name: Checkout Repo + - name: Checkout uses: actions/checkout@v4 with: + persist-credentials: false # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - - name: Setup Node.js 22.x + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: "https://registry.npmjs.org" + + - name: Update npm + run: npm install -g npm@11.11.1 + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: Create Release Pull Request + id: changesets + uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3 + with: + version: npm run version + commitMode: github-api + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check for unpublished package versions + if: steps.changesets.outputs.hasChangesets == 'false' + id: publish-check + run: node .github/scripts/has-unpublished-packages.mjs + + publish: + name: Publish + needs: release + if: needs.release.outputs.should_publish == 'true' + environment: + name: npm + url: https://www.npmjs.com/package/preact-render-to-string + permissions: + contents: write + id-token: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install Node.js uses: actions/setup-node@v4 with: node-version: 22 - cache: npm registry-url: "https://registry.npmjs.org" - name: Update npm - run: npm install -g npm@latest + run: npm install -g npm@11.11.1 + + - name: Install dependencies + run: npm ci --ignore-scripts - - name: Install Dependencies - run: npm ci + - name: Build package + run: npm run build - - name: Create Release PR or Publish - uses: changesets/action@v1.5.3 + - name: Publish packages + uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3 with: - publish: npx changeset publish + publish: npm exec -- changeset publish + commitMode: github-api env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index 9d4a08a3..21790ca0 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "test:vitest": "vitest", "test:vitest:run": "vitest run", "format": "oxfmt --write .", + "version": "changeset version && npm install --package-lock-only --ignore-scripts", "prepublishOnly": "npm run build", "release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish" },