Skip to content

Commit

Permalink
feat(dry-run): print publish results in dry run, even if publish woul…
Browse files Browse the repository at this point in the history
…d be skipped
  • Loading branch information
mcous committed Mar 22, 2024
1 parent 126874f commit fa143ea
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 54 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/ci-cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,21 @@ jobs:
echo "::error::Expected release type to be 'patch', got '${{ steps.action-publish.outputs.type }}'"
exit 1
- id: action-publish-dry
name: Publish a dry run
uses: ./
with:
registry: http://localhost:4873
package: ${{ steps.setup.outputs.package }}/package.json
token: ${{ steps.setup.outputs.token }}
dry-run: true

- name: Check release output
if: ${{ steps.action-publish-dry.outputs.type != 'dry-run' }}
run: |
echo "::error::Expected release type to be 'dry-run', got '${{ steps.action-publish.outputs.type }}'"
exit 1
deploy:
if: ${{ github.ref == 'refs/heads/main' }}
name: Publish
Expand Down
44 changes: 22 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,17 @@ npm-publish exposes several output variables, which you can use in later steps o
+ run: echo "Version changed!"
```

| Name | Type | Description |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------------- |
| `id` | string | Package identifier of the release: `${name}@${version}` or empty if no release. |
| `type` | string | [Semver release type][], `initial` if first release, `different` if other change, or empty if no release. |
| `name` | string | Name of the package. |
| `version` | string | Version of the package. |
| `old-version` | string | Previously published version on `tag` or empty if no previous version on tag. |
| `tag` | string | [Distribution tag][npm-tag] the package was published to. |
| `access` | string | [Access level][npm-access] the package was published with, or `default` if scoped-package defaults were used. |
| `registry` | string | Registry the package was published to. |
| `dry-run` | boolean | Whether `npm publish` was run in "dry run" mode. |
| Name | Type | Description |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` | string | Package identifier of the release: `${name}@${version}` or empty if no release. |
| `type` | string | [Semver release type][], `initial` if first release, `different` if other change, `dry-run` if no release would happen in a dry run, or empty if no release. |
| `name` | string | Name of the package. |
| `version` | string | Version of the package. |
| `old-version` | string | Previously published version on `tag` or empty if no previous version on tag. |
| `tag` | string | [Distribution tag][npm-tag] the package was published to. |
| `access` | string | [Access level][npm-access] the package was published with, or `default` if scoped-package defaults were used. |
| `registry` | string | Registry the package was published to. |
| `dry-run` | boolean | Whether `npm publish` was run in "dry run" mode. |

[semver release type]: https://github.com/npm/node-semver#release_types

Expand Down Expand Up @@ -199,17 +199,17 @@ The `npmPublish()` function returns a promise of a `Results` object. In TypeScri
import type { Results } from "@jsdevtools/npm-publish";
```

| Name | Type | Description |
| ------------ | --------------- | --------------------------------------------------------------------------------------------------------------- |
| `id` | Optional string | Package identifier of the release: `${name}@${version}` or `undefined` if no release. |
| `type` | Optional string | [Semver release type][], `initial` if first release, `different` if other change, or `undefined` if no release. |
| `name` | string | Name of the package. |
| `version` | string | Version of the package. |
| `oldVersion` | Optional string | Previously published version on `tag` or `undefined` if no previous version. |
| `tag` | string | [Distribution tag][npm-tag] that the package was published to. |
| `access` | Optional string | [Access level][npm-access] the package was published with, or `undefined` if scoped-package defaults were used. |
| `registry` | `URL` | Registry the package was published to. |
| `dryRun` | boolean | Whether `npm publish` was run in "dry run" mode. |
| Name | Type | Description |
| ------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` | Optional string | Package identifier of the release: `${name}@${version}` or `undefined` if no release. |
| `type` | Optional string | [Semver release type][], `initial` if first release, `different` if other change, `dry-run` if no release would happen in a dry run, or `undefined` if no release. |
| `name` | string | Name of the package. |
| `version` | string | Version of the package. |
| `oldVersion` | Optional string | Previously published version on `tag` or `undefined` if no previous version. |
| `tag` | string | [Distribution tag][npm-tag] that the package was published to. |
| `access` | Optional string | [Access level][npm-access] the package was published with, or `undefined` if scoped-package defaults were used. |
| `registry` | `URL` | Registry the package was published to. |
| `dryRun` | boolean | Whether `npm publish` was run in "dry run" mode. |

## Command Line Interface

Expand Down
31 changes: 21 additions & 10 deletions dist/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions dist/main.js.map

Large diffs are not rendered by default.

27 changes: 22 additions & 5 deletions src/__tests__/format-publish-result.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import { describe, it, expect } from "vitest";
import * as subject from "../format-publish-result.js";
import type { PackageManifest } from "../read-manifest.js";
import type { NormalizedOptions } from "../normalize-options.js";
import type { PublishResult } from "../compare-and-publish/index.js";
import type {
PublishResult,
PublishFile,
} from "../compare-and-publish/index.js";

describe("formatPublishResult", () => {
it("should say if a publish was skipped", () => {
const result = subject.formatPublishResult(
{ name: "cool-package", version: "1.2.3" } as PackageManifest,
{} as NormalizedOptions,
{ id: undefined } as PublishResult
{ dryRun: { value: false } } as NormalizedOptions,
{ id: undefined, files: [] as PublishFile[] } as PublishResult
);

expect(result).toMatch(/cool-package@1\.2\.3.+skipped/);
expect(result).toMatch(/cool-package@1\.2\.3.+already published/);
});

it("should say if a publish was a dry run", () => {
Expand All @@ -26,7 +29,21 @@ describe("formatPublishResult", () => {
} as PublishResult
);

expect(result).toMatch(/cool-package@1\.2\.3.+DRY RUN/);
expect(result).toMatch(/DRY RUN/);
});

it("should say if a dry run would have skipped", () => {
const result = subject.formatPublishResult(
{ name: "cool-package", version: "1.2.3" } as PackageManifest,
{ dryRun: { value: true } } as NormalizedOptions,
{
id: "[email protected]",
files: [{ path: "cool-file-1", size: 1 }],
type: "dry-run",
} as PublishResult
);

expect(result).toMatch(/cool-package@1\.2\.3.+already published/);
});

it("should print files", () => {
Expand Down
25 changes: 24 additions & 1 deletion src/compare-and-publish/__tests__/compare-versions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe("compareVersions", () => {
const result = subject.compareVersions(
"0.0.0",
{ versions: [], "dist-tags": {} },
{ tag: { value: "next" } } as NormalizedOptions
{ tag: { value: "next" }, dryRun: { value: false } } as NormalizedOptions
);

expect(result).toEqual({
Expand All @@ -20,6 +20,7 @@ describe("compareVersions", () => {
it("should handle no known versions or dist tags", () => {
const result = subject.compareVersions("0.0.0", undefined, {
tag: { value: "next" },
dryRun: { value: false },
} as NormalizedOptions);

expect(result).toEqual({
Expand All @@ -35,6 +36,7 @@ describe("compareVersions", () => {
{
strategy: { value: "all" },
tag: { value: "next" },
dryRun: { value: false },
} as NormalizedOptions
);

Expand All @@ -51,6 +53,7 @@ describe("compareVersions", () => {
{
strategy: { value: "upgrade" },
tag: { value: "next" },
dryRun: { value: false },
} as NormalizedOptions
);

Expand All @@ -67,6 +70,7 @@ describe("compareVersions", () => {
{
strategy: { value: "all" },
tag: { value: "next" },
dryRun: { value: false },
} as NormalizedOptions
);

Expand All @@ -83,6 +87,7 @@ describe("compareVersions", () => {
{
strategy: { value: "upgrade" },
tag: { value: "next" },
dryRun: { value: false },
} as NormalizedOptions
);

Expand All @@ -99,6 +104,7 @@ describe("compareVersions", () => {
{
strategy: { value: "upgrade" },
tag: { value: "next" },
dryRun: { value: false },
} as NormalizedOptions
);

Expand All @@ -107,4 +113,21 @@ describe("compareVersions", () => {
oldVersion: "1.2.3",
});
});

it('should "release" anyway if dry run', () => {
const result = subject.compareVersions(
"4.5.6",
{ versions: ["1.2.3", "4.5.6"], "dist-tags": { next: "4.5.6" } },
{
strategy: { value: "all" },
tag: { value: "next" },
dryRun: { value: true },
} as NormalizedOptions
);

expect(result).toEqual({
type: "dry-run",
oldVersion: "4.5.6",
});
});
});
11 changes: 6 additions & 5 deletions src/compare-and-publish/compare-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import semverValid from "semver/functions/valid.js";

import { STRATEGY_ALL } from "../options.js";
import type { NormalizedOptions } from "../normalize-options.js";
import type { ReleaseType } from "../results.js";
import { INITIAL, DIFFERENT, DRY_RUN, type ReleaseType } from "../results.js";
import type { NpmViewData } from "../npm/index.js";

export interface VersionComparison {
type: ReleaseType | undefined;
oldVersion: string | undefined;
}

const INITIAL = "initial";
const DIFFERENT = "different";

/**
* Compare previously published versions with the package's current version.
*
Expand All @@ -29,7 +26,7 @@ export function compareVersions(
options: NormalizedOptions
): VersionComparison {
const { versions, "dist-tags": tags } = publishedVersions ?? {};
const { strategy, tag: publishTag } = options;
const { strategy, dryRun, tag: publishTag } = options;
const oldVersion = semverValid(tags?.[publishTag.value]) ?? undefined;
const isUnique = !versions?.includes(currentVersion);
let type: ReleaseType | undefined;
Expand All @@ -44,5 +41,9 @@ export function compareVersions(
}
}

if (type === undefined && dryRun.value) {
type = DRY_RUN;
}

return { type, oldVersion };
}
30 changes: 23 additions & 7 deletions src/format-publish-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import os from "node:os";

import type { PublishResult } from "./compare-and-publish/index.js";
import type { PackageManifest } from "./read-manifest.js";
import { DRY_RUN } from "./results.js";
import type { NormalizedOptions } from "./normalize-options.js";

const DRY_RUN_BANNER =
"=== DRY RUN === DRY RUN === DRY RUN === DRY RUN === DRY RUN ===";

const CONTENTS_BANNER = "=== Contents ===";

/**
* Format publish results into a string.
*
Expand All @@ -17,15 +23,25 @@ export function formatPublishResult(
options: NormalizedOptions,
result: PublishResult
): string {
if (result.id === undefined) {
return `🙅‍♀️ ${manifest.name}@${manifest.version} publish skipped.`;
const lines = [];

lines.push(
result.id === undefined || result.type === DRY_RUN
? `🙅‍♀️ ${manifest.name}@${manifest.version} already published.`
: `📦 ${result.id}`
);

if (result.id) {
lines.push(CONTENTS_BANNER);
}

for (const { path, size } of result.files) {
lines.push(`${formatSize(size)}\t${path}`);
}

return [
`📦 ${result.id}${options.dryRun.value ? " (DRY RUN)" : ""}`,
"=== Contents ===",
...result.files.map(({ path, size }) => `${formatSize(size)}\t${path}`),
].join(os.EOL);
return (
options.dryRun.value ? [DRY_RUN_BANNER, ...lines, DRY_RUN_BANNER] : lines
).join(os.EOL);
}

const formatSize = (size: number): string => {
Expand Down
8 changes: 7 additions & 1 deletion src/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import type { Access, Strategy } from "./options.js";
import type { ReleaseType as SemverReleaseType } from "semver";

/** Release type */
export type ReleaseType = SemverReleaseType | typeof INITIAL | typeof DIFFERENT;
export type ReleaseType =
| SemverReleaseType
| typeof INITIAL
| typeof DIFFERENT
| typeof DRY_RUN;

export const INITIAL = "initial";
export const DIFFERENT = "different";
export const DRY_RUN = "dry-run";

/** Results of the publish */
export interface Results {
Expand Down

0 comments on commit fa143ea

Please sign in to comment.