Skip to content

Commit

Permalink
Add --report-summary to publish command to save a report summary (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeguerin authored Mar 4, 2024
1 parent e428d82 commit 2b25e0f
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 23 deletions.
8 changes: 8 additions & 0 deletions .chronus/changes/publish-summary-2024-2-4-3-44-27.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: breaking, feature, fix, internal
changeKind: fix
packages:
- "@chronus/chronus"
---

Add `--report-summary` to `publish` command to save a report summary
8 changes: 7 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ jobs:
- run: node ./packages/chronus/cmd/cli.mjs pack --pack-destination ./artifacts
name: Pack

- run: node ./packages/chronus/cmd/cli.mjs publish "./artifacts/*.tgz" --access public --engine npm # Have to use npm as pnpm doesn't respect access.
# Have to use npm as pnpm doesn't respect access.
- run: node ./packages/chronus/cmd/cli.mjs publish "./artifacts/*.tgz" --access public --engine npm --report-summary ./publish-summary.json
name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Expand All @@ -61,3 +62,8 @@ jobs:
# name: Publish
# env:
# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- run: |
echo "Publish summary:"
cat ./publish-summary.json
name: Log publish summary
5 changes: 5 additions & 0 deletions packages/chronus/src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ async function main() {
type: "string",
choices: ["npm", "pnpm"] as const,
description: "Engine to use (npm or pnpm, default to use pnpm in a pnpm workspace and npm otherwise)",
})
.option("report-summary", {
type: "string",
description: "Save the list of published packages.",
}),
withReporter((args) =>
publish({
Expand All @@ -120,6 +124,7 @@ async function main() {
access: args.access,
registry: args.registry,
engine: args.engine,
reportSummary: args.reportSummary && resolvePath(process.cwd(), args.reportSummary),
}),
),
)
Expand Down
65 changes: 57 additions & 8 deletions packages/chronus/src/cli/commands/publish.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import pc from "picocolors";
import { publishPackage } from "../../publish/publish-package.js";
import type { PublishPackageResult, PublishSummary } from "../../publish/types.js";
import type { Reporter } from "../../reporters/index.js";
import { findUnpublishedPackages, findUnpublishedWorkspacePackages } from "../../unpublished-packages/index.js";
import { ChronusError, NodeChronusHost, prettyBytes, resolvePath, type ChronusHost } from "../../utils/index.js";
import { loadChronusWorkspace } from "../../workspace/index.js";
import { loadChronusWorkspace, type ChronusWorkspace } from "../../workspace/index.js";

export interface PublishOptions {
readonly reporter: Reporter;
Expand All @@ -12,35 +13,76 @@ export interface PublishOptions {
readonly access?: "public" | "restricted";
readonly registry?: string;
readonly engine?: "pnpm" | "npm";
readonly reportSummary?: string;
}

export async function publish({ reporter, pattern, ...others }: PublishOptions) {
export async function publish({ reporter, pattern, reportSummary, ...others }: PublishOptions) {
const host = NodeChronusHost;
const filesOrFolders = await host.glob(pattern);
let results: Record<string, PublishPackageResult>;
let workspace: ChronusWorkspace | undefined;
if (filesOrFolders.length > 1 || filesOrFolders[0]?.endsWith(".tgz")) {
const tgzFiles = filesOrFolders.filter((file) => file.endsWith(".tgz"));
if (tgzFiles.length !== filesOrFolders.length) {
throw new ChronusError(`Can only bulk publish tarballs or a single workspace at a time.`);
}
await publishTarballs(host, tgzFiles, { reporter, ...others });
try {
workspace = await loadChronusWorkspace(host, process.cwd());
} catch (e) {
// Don't need to be in a workspace for this.
}

results = await publishTarballs(host, tgzFiles, { reporter, ...others });
} else {
await publishWorkspacePackages(host, pattern, { reporter, ...others });
workspace = workspace = await loadChronusWorkspace(host, pattern);
results = await publishWorkspacePackages(workspace, { reporter, ...others });
}

if (reportSummary) {
const summary = createPublishSummary(results, workspace);
await host.writeFile(reportSummary, JSON.stringify(summary, null, 2));
}
}

function createPublishSummary(
results: Record<string, PublishPackageResult>,
workspace: ChronusWorkspace | undefined,
): PublishSummary {
let hasFailure = false;
let hasSuccess = false;
const items = Object.values(results);
if (items.length === 0) {
return { status: "success", packages: {} };
}
for (const item of items) {
if (item.published) {
hasSuccess = true;
} else {
hasFailure = true;
}
}

return {
status: hasSuccess && hasFailure ? "partial" : hasSuccess ? "success" : "failed",
packages: results,
};
}

async function publishWorkspacePackages(
host: ChronusHost,
workspaceDir: string,
workspace: ChronusWorkspace,
{ reporter, ...others }: Omit<PublishOptions, "pattern">,
) {
const workspace = await loadChronusWorkspace(host, workspaceDir);
): Promise<Record<string, PublishPackageResult>> {
const packageToPublish = await findUnpublishedWorkspacePackages(workspace);
if (packageToPublish.length === 0) {
reporter.log(pc.green("All packages are already published."));
return {};
}
const results: Record<string, PublishPackageResult> = {};

for (const pkg of packageToPublish) {
await reporter.task(`${pc.yellow(pkg.name)} publishing`, async (task) => {
const result = await publishPackage(pkg, resolvePath(workspace.path, pkg.relativePath), others);
results[pkg.name] = result;
if (result.published) {
task.update(
`${pc.yellow(pkg.name)} published at version ${pc.cyan(pkg.version)} (${pc.magenta(prettyBytes(result.size))})`,
Expand All @@ -51,6 +93,8 @@ async function publishWorkspacePackages(
}
});
}

return results;
}

async function publishTarballs(
Expand All @@ -62,9 +106,13 @@ async function publishTarballs(
if (unpublished.length === 0) {
reporter.log(pc.green("All tarballs are already published."));
}

const results: Record<string, PublishPackageResult> = {};

for (const pkg of unpublished) {
await reporter.task(`${pc.yellow(pkg.name)} publishing`, async (task) => {
const result = await publishPackage(pkg, pkg.tarballPath, others);
results[pkg.name] = result;
if (result.published) {
task.update(
`${pc.yellow(pkg.name)} published at version ${pc.cyan(pkg.version)} (${pc.magenta(prettyBytes(result.size))})`,
Expand All @@ -75,4 +123,5 @@ async function publishTarballs(
}
});
}
return results;
}
17 changes: 3 additions & 14 deletions packages/chronus/src/publish/publish-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { execAsync, type ExecResult } from "../utils/exec-async.js";
import { getDirectoryPath, getLastJsonObject, lookup, NodeChronusHost } from "../utils/index.js";
import { createPnpmWorkspaceManager } from "../workspace-manager/pnpm.js";
import type { PackageBase } from "../workspace-manager/types.js";
import type { PublishPackageResult } from "./types.js";

export interface PublishPackageOptions {
readonly otp?: string;
Expand All @@ -13,20 +14,6 @@ export interface PublishPackageOptions {
readonly engine?: "npm" | "pnpm";
}

export type PublishPackageResult = PublishedPackageSuccess | PublishedPackageFailure;

export interface PublishedPackageSuccess {
readonly published: true;
readonly name: string;
readonly version: string;
readonly size: number;
readonly unpackedSize: number;
}

export interface PublishedPackageFailure {
readonly published: false;
}

/** Npm publish json output. */
interface NpmPublishResult {
readonly id: string;
Expand Down Expand Up @@ -158,6 +145,8 @@ function processError(pkg: PackageBase, result: ExecResult): PublishPackageResul

return {
published: false,
name: pkg.name,
version: pkg.version,
};
}

Expand Down
22 changes: 22 additions & 0 deletions packages/chronus/src/publish/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export type PublishSummaryStatus = "success" | "partial" | "failed";

export type PublishPackageResult = PublishedPackageSuccess | PublishedPackageFailure;

export interface PublishedPackageSuccess {
readonly published: true;
readonly name: string;
readonly version: string;
readonly size: number;
readonly unpackedSize: number;
}

export interface PublishedPackageFailure {
readonly published: false;
readonly name: string;
readonly version: string;
}

export interface PublishSummary {
status: PublishSummaryStatus;
packages: Record<string, PublishPackageResult>;
}

0 comments on commit 2b25e0f

Please sign in to comment.