@pob/version 5.1.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -15
- package/README.md +147 -10
- package/dist/index-node.mjs +1482 -0
- package/dist/index-node.mjs.map +1 -0
- package/package.json +77 -24
- package/src/commands/version.test.ts +120 -0
- package/src/commands/version.ts +956 -0
- package/src/index.ts +13 -0
- package/src/missing-types.d.ts +10 -0
- package/src/pm/BunPackageManager.ts +29 -0
- package/src/pm/PackageManager.ts +90 -0
- package/src/pm/PnpmPackageManager.ts +23 -0
- package/src/pm/YarnPackageManager.ts +44 -0
- package/src/utils/UsageError.ts +6 -0
- package/src/utils/bumpTypeUtils.test.ts +65 -0
- package/src/utils/bumpTypeUtils.ts +111 -0
- package/src/utils/conventionalChangelogUtils.test.ts +762 -0
- package/src/utils/conventionalChangelogUtils.ts +104 -0
- package/src/utils/conventionalCommitConfigUtils.ts +19 -0
- package/src/utils/execCommand.ts +214 -0
- package/src/utils/generatorUtils.ts +11 -0
- package/src/utils/gitUtils.ts +193 -0
- package/src/utils/githubUtils.ts +120 -0
- package/src/utils/mapUtils.ts +7 -0
- package/src/utils/mapWorkspaces.test.ts +89 -0
- package/src/utils/packageDependenciesUtils.test.ts +25 -0
- package/src/utils/packageDependenciesUtils.ts +80 -0
- package/src/utils/packageUtils.test.ts +32 -0
- package/src/utils/packageUtils.ts +129 -0
- package/src/utils/updateChangelog.ts +39 -0
- package/src/utils/workspaceUtils.ts +142 -0
- package/.editorconfig +0 -13
- package/.eslintrc.json +0 -4
- package/CHANGELOG.md +0 -108
- package/generate-index.js +0 -13
- package/lib/index.d.ts +0 -8
- package/lib/index.js +0 -5
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
|
|
4
|
+
import "./commands/version.ts";
|
|
5
|
+
|
|
6
|
+
// relative to dist directory
|
|
7
|
+
const pkg = JSON.parse(
|
|
8
|
+
// eslint-disable-next-line unicorn/prefer-json-parse-buffer
|
|
9
|
+
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
program.name(pkg.name).description(pkg.description).version(pkg.version);
|
|
13
|
+
program.parse();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// declare module "conventional-changelog-core" {
|
|
2
|
+
// export default function conventionalChangelogCore(
|
|
3
|
+
// options: any,
|
|
4
|
+
// context?: any,
|
|
5
|
+
// gitRawCommitsOpts?: any,
|
|
6
|
+
// parserOpts?: any,
|
|
7
|
+
// writerOpts?: any,
|
|
8
|
+
// gitRawExecOpts?: any,
|
|
9
|
+
// ): Readable;
|
|
10
|
+
// }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { execCommand } from "../utils/execCommand.ts";
|
|
2
|
+
import type {
|
|
3
|
+
PackageManager,
|
|
4
|
+
PackageManagerPublishOptions,
|
|
5
|
+
} from "./PackageManager.ts";
|
|
6
|
+
|
|
7
|
+
export const BunPackageManager: PackageManager = {
|
|
8
|
+
async runScript(workspace, scriptName) {
|
|
9
|
+
await execCommand(workspace, ["bun", "run", scriptName], "inherit");
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
async publish(workspace, options?: PackageManagerPublishOptions) {
|
|
13
|
+
if (options?.provenance) {
|
|
14
|
+
// Use bun pack for provenance support
|
|
15
|
+
// See: https://github.com/oven-sh/bun/issues/15601
|
|
16
|
+
const packResult = await execCommand(workspace, ["bun", "pm", "pack"]);
|
|
17
|
+
// Extract .tgz filename from output (find line ending with .tgz)
|
|
18
|
+
const lines = packResult.stdout.trim().split("\n");
|
|
19
|
+
const tgzPath =
|
|
20
|
+
lines.find((line) => line.endsWith(".tgz")) ?? lines.at(-1);
|
|
21
|
+
if (!tgzPath) {
|
|
22
|
+
throw new Error("Failed to extract .tgz path from bun pack output");
|
|
23
|
+
}
|
|
24
|
+
await execCommand(workspace, ["npm", "publish", "--provenance", tgzPath]);
|
|
25
|
+
} else {
|
|
26
|
+
await execCommand(workspace, ["bun", "publish"], "inherit");
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import type { Workspace } from "../utils/packageUtils.ts";
|
|
3
|
+
import { BunPackageManager } from "./BunPackageManager.ts";
|
|
4
|
+
import { PnpmPackageManager } from "./PnpmPackageManager.ts";
|
|
5
|
+
import { YarnPackageManager } from "./YarnPackageManager.ts";
|
|
6
|
+
|
|
7
|
+
export interface PackageManagerPublishOptions {
|
|
8
|
+
provenance?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface PackageManager {
|
|
12
|
+
installOnPackageContentChange?: (rootWorkspace: Workspace) => Promise<void>;
|
|
13
|
+
runScript: (workspace: Workspace, scriptName: string) => Promise<void>;
|
|
14
|
+
publish: (
|
|
15
|
+
workspace: Workspace,
|
|
16
|
+
options?: PackageManagerPublishOptions,
|
|
17
|
+
) => Promise<void>;
|
|
18
|
+
publishWorkspaces?: (
|
|
19
|
+
rootWorkspace: Workspace,
|
|
20
|
+
options?: PackageManagerPublishOptions,
|
|
21
|
+
) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const autoDetectPackageManager = (
|
|
25
|
+
rootWorkspace: Workspace,
|
|
26
|
+
): PackageManager => {
|
|
27
|
+
const hasYarnLock = existsSync(`${rootWorkspace.cwd}/yarn.lock`);
|
|
28
|
+
const hasBunLockLegacy = existsSync(`${rootWorkspace.cwd}/bun.lockb`);
|
|
29
|
+
const hasBunLock = existsSync(`${rootWorkspace.cwd}/bun.lock`);
|
|
30
|
+
const hasNpmPackageLock = existsSync(
|
|
31
|
+
`${rootWorkspace.cwd}/package-lock.json`,
|
|
32
|
+
);
|
|
33
|
+
const hasPnpmLock = existsSync(`${rootWorkspace.cwd}/pnpm-lock.yaml`);
|
|
34
|
+
|
|
35
|
+
if (
|
|
36
|
+
[
|
|
37
|
+
hasYarnLock,
|
|
38
|
+
hasBunLockLegacy,
|
|
39
|
+
hasBunLock,
|
|
40
|
+
hasNpmPackageLock,
|
|
41
|
+
hasPnpmLock,
|
|
42
|
+
].filter(Boolean).length > 1
|
|
43
|
+
) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Multiple lock files detected in workspace at ${rootWorkspace.cwd}. Please ensure only one lock file is present, or pass --package-manager option to bypass auto-detection.`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (hasYarnLock) {
|
|
50
|
+
return YarnPackageManager;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (hasBunLockLegacy || hasBunLock) {
|
|
54
|
+
return BunPackageManager;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (hasPnpmLock) {
|
|
58
|
+
return PnpmPackageManager;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (hasNpmPackageLock) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
"NPM is not currently supported as a package manager. Please migrate to Yarn or Bun, or open an issue to request support.",
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw new Error(
|
|
68
|
+
`No lock file detected in workspace at ${rootWorkspace.cwd}. Please ensure a supported lock file is present, or pass --package-manager option to bypass auto-detection.`,
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const getPackageManager = (
|
|
73
|
+
rootWorkspace: Workspace,
|
|
74
|
+
specifiedPackageManager?: "bun" | "pnpm" | "yarn",
|
|
75
|
+
): PackageManager => {
|
|
76
|
+
switch (specifiedPackageManager) {
|
|
77
|
+
case "bun":
|
|
78
|
+
return BunPackageManager;
|
|
79
|
+
case "yarn":
|
|
80
|
+
return YarnPackageManager;
|
|
81
|
+
case "pnpm":
|
|
82
|
+
return PnpmPackageManager;
|
|
83
|
+
case undefined:
|
|
84
|
+
default: {
|
|
85
|
+
throw new Error(
|
|
86
|
+
"Invalid package manager specified. Supported values are 'bun' and 'yarn'.",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { execCommand } from "../utils/execCommand.ts";
|
|
2
|
+
import type {
|
|
3
|
+
PackageManager,
|
|
4
|
+
PackageManagerPublishOptions,
|
|
5
|
+
} from "./PackageManager.ts";
|
|
6
|
+
|
|
7
|
+
export const PnpmPackageManager: PackageManager = {
|
|
8
|
+
async runScript(workspace, scriptName) {
|
|
9
|
+
await execCommand(workspace, ["pnpm", "run", scriptName], "inherit");
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
async publish(workspace, options?: PackageManagerPublishOptions) {
|
|
13
|
+
if (options?.provenance) {
|
|
14
|
+
await execCommand(
|
|
15
|
+
workspace,
|
|
16
|
+
["pnpm", "publish", "--provenance"],
|
|
17
|
+
"inherit",
|
|
18
|
+
);
|
|
19
|
+
} else {
|
|
20
|
+
await execCommand(workspace, ["pnpm", "publish"], "inherit");
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { execCommand } from "../utils/execCommand.ts";
|
|
2
|
+
import type { Workspace } from "../utils/packageUtils.ts";
|
|
3
|
+
import type {
|
|
4
|
+
PackageManager,
|
|
5
|
+
PackageManagerPublishOptions,
|
|
6
|
+
} from "./PackageManager.ts";
|
|
7
|
+
|
|
8
|
+
export const YarnPackageManager: PackageManager = {
|
|
9
|
+
async installOnPackageContentChange(rootWorkspace: Workspace) {
|
|
10
|
+
await execCommand(rootWorkspace, ["yarn", "install"], "inherit");
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
async runScript(workspace: Workspace, scriptName: string) {
|
|
14
|
+
await execCommand(workspace, ["yarn", "run", scriptName], "inherit");
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
async publish(workspace: Workspace, options?: PackageManagerPublishOptions) {
|
|
18
|
+
const publishArgs = ["yarn", "npm", "publish"];
|
|
19
|
+
if (options?.provenance) {
|
|
20
|
+
publishArgs.push("--provenance");
|
|
21
|
+
}
|
|
22
|
+
await execCommand(workspace, publishArgs, "inherit");
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
async publishWorkspaces(
|
|
26
|
+
rootWorkspace: Workspace,
|
|
27
|
+
options?: PackageManagerPublishOptions,
|
|
28
|
+
) {
|
|
29
|
+
const publishArgs = [
|
|
30
|
+
"yarn",
|
|
31
|
+
"workspaces",
|
|
32
|
+
"foreach",
|
|
33
|
+
"--all",
|
|
34
|
+
"--parallel",
|
|
35
|
+
"--no-private",
|
|
36
|
+
"npm",
|
|
37
|
+
"publish",
|
|
38
|
+
];
|
|
39
|
+
if (options?.provenance) {
|
|
40
|
+
publishArgs.push("--provenance");
|
|
41
|
+
}
|
|
42
|
+
await execCommand(rootWorkspace, publishArgs, "inherit");
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { calcBumpRange } from "./bumpTypeUtils.ts";
|
|
3
|
+
import type { Workspace } from "./packageUtils.ts";
|
|
4
|
+
|
|
5
|
+
const workspace: Workspace = {
|
|
6
|
+
cwd: "/repo/packages/foo",
|
|
7
|
+
relativeCwd: "packages/foo",
|
|
8
|
+
pkg: { name: "foo", version: "1.0.0" },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
describe("calcBumpRange", () => {
|
|
12
|
+
it("keeps bare * unchanged", () => {
|
|
13
|
+
expect(calcBumpRange(workspace, "*", "2.0.0")).toBe("*");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("keeps workspace:* unchanged", () => {
|
|
17
|
+
expect(calcBumpRange(workspace, "workspace:*", "2.0.0")).toBe(
|
|
18
|
+
"workspace:*",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("keeps workspace:^ unchanged", () => {
|
|
23
|
+
expect(calcBumpRange(workspace, "workspace:^", "2.0.0")).toBe(
|
|
24
|
+
"workspace:^",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("keeps workspace:~ unchanged", () => {
|
|
29
|
+
expect(calcBumpRange(workspace, "workspace:~", "2.0.0")).toBe(
|
|
30
|
+
"workspace:~",
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("keeps workspace:<relative path> unchanged", () => {
|
|
35
|
+
expect(calcBumpRange(workspace, "workspace:packages/foo", "2.0.0")).toBe(
|
|
36
|
+
"workspace:packages/foo",
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("bumps workspace:^x.y.z ranges", () => {
|
|
41
|
+
expect(calcBumpRange(workspace, "workspace:^1.0.0", "2.0.0")).toBe(
|
|
42
|
+
"workspace:^2.0.0",
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("bumps workspace:~x.y.z ranges", () => {
|
|
47
|
+
expect(calcBumpRange(workspace, "workspace:~1.0.0", "2.0.0")).toBe(
|
|
48
|
+
"workspace:~2.0.0",
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("bumps plain ^x.y.z ranges", () => {
|
|
53
|
+
expect(calcBumpRange(workspace, "^1.0.0", "2.0.0")).toBe("^2.0.0");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("bumps exact x.y.z versions", () => {
|
|
57
|
+
expect(calcBumpRange(workspace, "1.0.0", "2.0.0")).toBe("2.0.0");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("throws on an unsupported range", () => {
|
|
61
|
+
expect(() => calcBumpRange(workspace, "1.x", "2.0.0")).toThrow(
|
|
62
|
+
/Couldn't bump range/,
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import { UsageError } from "./UsageError.ts";
|
|
3
|
+
import type { Workspace } from "./packageUtils.ts";
|
|
4
|
+
import { getWorkspaceName } from "./workspaceUtils.ts";
|
|
5
|
+
|
|
6
|
+
export type BumpType = "major" | "minor" | "patch";
|
|
7
|
+
|
|
8
|
+
// https://github.com/yarnpkg/berry/blob/506ded5f5f5a89553435940c74f1d857fd685a42/packages/plugin-version/sources/versionUtils.ts#L10
|
|
9
|
+
// Basically we only support auto-upgrading the ranges that are very simple (^x.y.z, ~x.y.z, >=x.y.z, and of course x.y.z)
|
|
10
|
+
const SUPPORTED_UPGRADE_REGEXP =
|
|
11
|
+
// eslint-disable-next-line regexp/no-unused-capturing-group
|
|
12
|
+
/^((?:>=|[~^])?)(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-z-][0-9a-z-]*)(\.(0|[1-9]\d*|\d*[a-z-][0-9a-z-]*))*)?(\+[0-9a-z-]+(\.[0-9a-z-]+)*)?$/i;
|
|
13
|
+
|
|
14
|
+
const yarnWorkspaceProtocol = "workspace:";
|
|
15
|
+
|
|
16
|
+
export const calcBumpRange = (
|
|
17
|
+
workspace: Workspace,
|
|
18
|
+
range: string,
|
|
19
|
+
newVersion: string,
|
|
20
|
+
): string => {
|
|
21
|
+
if (range === "*") {
|
|
22
|
+
return range;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let useWorkspaceProtocol = false;
|
|
26
|
+
|
|
27
|
+
if (range.startsWith(yarnWorkspaceProtocol)) {
|
|
28
|
+
const slicedRange = range.slice(yarnWorkspaceProtocol.length);
|
|
29
|
+
|
|
30
|
+
// Workspaces referenced through their path never get upgraded ("workspace:packages/yarnpkg-core")
|
|
31
|
+
if (slicedRange === workspace.relativeCwd) {
|
|
32
|
+
return range;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (slicedRange === "*" || slicedRange === "^" || slicedRange === "~") {
|
|
36
|
+
return range;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
range = slicedRange;
|
|
40
|
+
useWorkspaceProtocol = true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const parsed = SUPPORTED_UPGRADE_REGEXP.exec(range);
|
|
44
|
+
if (!parsed) {
|
|
45
|
+
const workspaceName = getWorkspaceName(workspace);
|
|
46
|
+
throw new Error(`Couldn't bump range ${range} in ${workspaceName}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return `${useWorkspaceProtocol ? yarnWorkspaceProtocol : ""}${parsed[1] ?? ""}${newVersion}`;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getHighestBumpType = (bumpTypes: BumpType[]): BumpType => {
|
|
53
|
+
if (bumpTypes.includes("major")) {
|
|
54
|
+
return "major";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (bumpTypes.includes("minor")) {
|
|
58
|
+
return "minor";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return "patch";
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const calcBumpType = (
|
|
65
|
+
bumpType: BumpType,
|
|
66
|
+
maxBumpType: BumpType,
|
|
67
|
+
): BumpType => {
|
|
68
|
+
if (maxBumpType === "major") {
|
|
69
|
+
return bumpType;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (maxBumpType === "minor") {
|
|
73
|
+
return bumpType === "major" || bumpType === "minor" ? "minor" : "patch";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return "patch";
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const incVersion = (version: string, bumpType: BumpType): string | null => {
|
|
80
|
+
// handle breaking of 0.x
|
|
81
|
+
if (bumpType === "major" && semver.major(version) === 0) {
|
|
82
|
+
bumpType = "minor";
|
|
83
|
+
}
|
|
84
|
+
return semver.inc(version, bumpType);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const incrementVersion = (
|
|
88
|
+
workspace: Workspace,
|
|
89
|
+
currentVersion: string,
|
|
90
|
+
bumpType: BumpType,
|
|
91
|
+
): string => {
|
|
92
|
+
const newVersion = incVersion(currentVersion, bumpType);
|
|
93
|
+
|
|
94
|
+
if (!newVersion) {
|
|
95
|
+
throw new UsageError(
|
|
96
|
+
`Could not determine next version for "${getWorkspaceName(
|
|
97
|
+
workspace,
|
|
98
|
+
)}" (currentVersion: ${currentVersion}, bumpType: ${bumpType}})`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return newVersion;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// const createPrerelease = (
|
|
106
|
+
// version: string,
|
|
107
|
+
// prereleaseType: ReleaseType,
|
|
108
|
+
// prereleaseId: string,
|
|
109
|
+
// ) => {
|
|
110
|
+
// return semver.inc(version, prereleaseType, prereleaseId);
|
|
111
|
+
// };
|