Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
88 changes: 88 additions & 0 deletions .github/scripts/has-unpublished-packages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { appendFileSync } from "node:fs";
import { readdir, readFile } from "node:fs/promises";
import path from "node:path";

const ignoredDirectories = new Set([
".git",
"dist",
"node_modules",
]);

async function findPackageManifests(directory) {
const entries = await readdir(directory, { withFileTypes: true });
const manifests = [];

for (const entry of entries) {
const fullPath = path.join(directory, entry.name);

if (entry.isDirectory()) {
if (!ignoredDirectories.has(entry.name)) {
manifests.push(...await findPackageManifests(fullPath));
}
} else if (entry.isFile() && entry.name === "package.json") {
const pkg = JSON.parse(await readFile(fullPath, "utf8"));

if (!pkg.private && pkg.name && pkg.version) {
manifests.push({ name: pkg.name, version: pkg.version });
}
}
}

return manifests;
}

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 packages = (await findPackageManifests(process.cwd()))
.sort((a, b) => a.name.localeCompare(b.name));
let hasUnpublished = false;

for (const pkg of packages) {
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`);
hasUnpublished = true;
}
}

const output = [
`has_unpublished=${String(hasUnpublished)}`,
`should_publish=${String(hasUnpublished)}`,
].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);
});
7 changes: 6 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
has_changesets: ${{ steps.changesets.outputs.hasChangesets }}
has_unpublished_packages: ${{ steps.unpublished.outputs.has_unpublished }}
permissions:
contents: write
issues: read
Expand All @@ -30,6 +31,10 @@ jobs:
- name: Update npm
run: npm install -g npm@11.11

- name: Check for unpublished package versions
id: unpublished
run: node .github/scripts/has-unpublished-packages.mjs

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
Expand Down Expand Up @@ -63,7 +68,7 @@ jobs:
publish:
name: Publish
needs: release
if: needs.release.outputs.has_changesets == 'false'
if: needs.release.outputs.has_changesets == 'false' && needs.release.outputs.has_unpublished_packages == 'true'
runs-on: ubuntu-latest
environment:
name: npm
Expand Down
Loading