Skip to content

Commit

Permalink
List unpublished packages
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeguerin committed Feb 25, 2024
1 parent 80fa58b commit 5f8a788
Show file tree
Hide file tree
Showing 9 changed files with 776 additions and 38 deletions.
2 changes: 2 additions & 0 deletions cspell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ dictionaries:
- node
- typescript
words:
- ETARGET
- pacote
- picocolors
ignorePaths:
- "**/node_modules/**"
Expand Down
2 changes: 2 additions & 0 deletions packages/chronus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"globby": "^14.0.1",
"js-yaml": "^4.1.0",
"micromatch": "^4.0.5",
"pacote": "^17.0.6",
"picocolors": "^1.0.0",
"pluralize": "^8.0.0",
"prettier": "^3.2.5",
Expand All @@ -54,6 +55,7 @@
"@types/micromatch": "^4.0.6",
"@types/node": "^20.11.19",
"@types/node-fetch": "^2.6.11",
"@types/pacote": "^11.1.8",
"@types/pluralize": "^0.0.33",
"@types/prompts": "^2.4.9",
"@types/semver": "^7.5.7",
Expand Down
15 changes: 14 additions & 1 deletion packages/chronus/src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "source-map-support/register.js";
import yargs from "yargs";
import { addChangeset } from "./commands/add-changeset.js";
import { applyChangesets } from "./commands/apply-changesets.js";
import { listPendingPublish } from "./commands/list-pending-publish.js";
import { showStatus } from "./commands/show-status.js";
import { verifyChangeset } from "./commands/verify-changeset.js";

Expand All @@ -21,7 +22,7 @@ async function main() {
description: "Output debug log messages.",
default: false,
})
.command("add", "Add a new changeset", () => addChangeset(process.cwd()))
.command("add", "Add a new change description", () => addChangeset(process.cwd()))
.command("verify", "Verify all packages changes have been documented", () => verifyChangeset(process.cwd()))
.command(
"version",
Expand Down Expand Up @@ -57,6 +58,18 @@ async function main() {
}),
(args) => showStatus(process.cwd(), { ignorePolicies: args.ignorePolicies, only: args.only }),
)
.command(
["ls-pending-publish", "list-pending-publish"],
"Find packages that have not been published",
(cmd) =>
cmd.option("json", {
type: "boolean",
description: "Render the output as JSON",
default: false,
}),
(args) => listPendingPublish(process.cwd(), { json: args.json }),
)
.demandCommand(1, "You need at least one command before moving on")
.parse();
}

Expand Down
29 changes: 29 additions & 0 deletions packages/chronus/src/cli/commands/list-pending-publish.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pc from "picocolors";
import { findUnpublishedPackages } from "../../unpublished-packages/find-unpublished-packages.js";
import { NodeChronusHost } from "../../utils/node-host.js";
import { loadChronusWorkspace } from "../../workspace/index.js";

export interface ListPendingPublishOptions {
readonly json?: boolean;
}

export async function listPendingPublish(dir: string, options?: ListPendingPublishOptions) {
const host = NodeChronusHost;
const workspace = await loadChronusWorkspace(host, dir);

const packages = await findUnpublishedPackages(workspace);
if (options?.json) {
log(JSON.stringify(packages, null, 2));
} else {
log("Packages with unpublished versions:");
for (const pkg of packages) {
log(`- ${pkg.name} ${pc.cyan(pkg.version)}`);
}
log();
}
}

function log(...args: any[]) {
// eslint-disable-next-line no-console
console.log(...args);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import pacote from "pacote";
import type { ChronusWorkspace } from "../index.js";
import type { Package } from "../workspace-manager/types.js";

export async function findUnpublishedPackages(workspace: ChronusWorkspace): Promise<Package[]> {
const data = await Promise.all(
workspace.packages.map(async (pkg) => [pkg, await isPackageVersionPublished(pkg)] as const),
);
return data.filter(([, published]) => !published).map(([pkg]) => pkg);
}

async function isPackageVersionPublished(pkg: Package): Promise<boolean> {
try {
const manifest = await pacote.manifest(`${pkg.name}@${pkg.version}`);
return manifest.version === pkg.version;
} catch (e: unknown) {
if (isPacoteError(e) && ((e.code === "ETARGET" && e.type === "version") || e.code === "E404")) {
return false;
}
throw e;
}
}

function isPacoteError(e: unknown): e is PacoteError | HttpError {
return typeof e === "object" && e !== null && "code" in e;
}

interface HttpError {
readonly code: "E404";
}
interface PacoteError {
readonly code: "ETARGET";
readonly type: "version";
readonly wanted: string;
readonly versions: string[];
readonly name: string;
readonly distTags: Record<string, string>;
readonly defaultTag: string;
}
1 change: 1 addition & 0 deletions packages/chronus/src/unpublished-packages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { findUnpublishedPackages } from "./find-unpublished-packages.js";
6 changes: 3 additions & 3 deletions packages/chronus/src/utils/exec-async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { SpawnOptions } from "child_process";
import crosspawn from "cross-spawn";

export interface ExecResult {
code: number | null;
stdout: Buffer;
stderr: Buffer;
readonly code: number | null;
readonly stdout: Buffer;
readonly stderr: Buffer;
}
export function execAsync(cmd: string, args: string[], opts: SpawnOptions): Promise<ExecResult> {
return new Promise((resolve, reject) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/github-pr-commenter/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chronus/github-pr-commenter",
"version": "0.3.0",
"version": "0.4.0",
"description": "chronus",
"main": "dist/index.js",
"type": "module",
Expand Down
Loading

0 comments on commit 5f8a788

Please sign in to comment.