From fb57e03d793e1f67bf416ed6359c11ca3a418857 Mon Sep 17 00:00:00 2001
From: Matt Hamlin
Date: Fri, 17 May 2024 13:07:11 -0400
Subject: [PATCH] 0.2.0
---
apps/docs/app/page.tsx | 23 ++--
apps/docs/public/schema.json | 5 +
packages/one-version/CHANGELOG.md | 16 +++
packages/one-version/README.md | 18 ++-
.../bun-configured-pinned/bun.lockb | Bin 0 -> 4258 bytes
.../libs/pkg-a/package.json | 14 ++
.../libs/pkg-b/package.json | 14 ++
.../libs/pkg-c/package.json | 14 ++
.../one-version.config.jsonc | 5 +
.../bun-configured-pinned/package.json | 6 +
.../__tests__/one-version.test.mjs | 128 +++++++++++++++++-
packages/one-version/one-version.mjs | 119 ++++++++++++++--
packages/one-version/package.json | 2 +-
13 files changed, 334 insertions(+), 30 deletions(-)
create mode 100755 packages/one-version/__fixtures__/bun-configured-pinned/bun.lockb
create mode 100644 packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-a/package.json
create mode 100644 packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-b/package.json
create mode 100644 packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-c/package.json
create mode 100644 packages/one-version/__fixtures__/bun-configured-pinned/one-version.config.jsonc
create mode 100644 packages/one-version/__fixtures__/bun-configured-pinned/package.json
diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx
index 7135a42..8b554e4 100644
--- a/apps/docs/app/page.tsx
+++ b/apps/docs/app/page.tsx
@@ -34,6 +34,10 @@ export default function Home() {
One Version is a strict dependency conformance tool for monorepos, managing dependencies across repos has
never been easier!
+
+ This tool ensures that all workspaces in your monorepo are using the same version of a dependency, and also an
+ (opt-in) strict versioning strategy to ensure that all dependencies are pinned to an exact version.
+
@@ -142,21 +146,22 @@ export default function Home() {
{`{
- // The schema for the configuration file
"$schema": "https://one-version.vercel.app/schema.json",
- // One of the supported package managers:
- // 'bun', 'pnpm', 'npm', 'yarn-classic', 'yarn-berry'
+ // one of: "bun", "yarn-berry", "yarn-classic", "pnpm", "npm"
+ // by default it will try to detect the package manager based on the presence of a lockfile
"packageManager": "bun",
- // A mapping of overrides, where the key is the dependency name, and the value is a map of
- // version specifier to an array of workspaces that are allowed to use that version.
+ // A mapping of dependencies, and which workspaces are "allowed" to use different versions
"overrides": {
"react": {
- // in this example, pkg-a is allowed to use react@18
- // and pkg-b is allowed to use react@17
"18.0.0": ["pkg-a"],
- "17.0.0": ["pkg-b"]
+ // Wildcards are supported, and will capture any workspaces!
+ "17.0.0": ["*"]
}
- }
+ },
+ // one of: "pin", "loose", defaults to "loose" if not provided
+ // pin: all dependencies and devDependencies must use an exact version
+ // meaning no ranges (\`^\`, \`~\`, \`.x\`, etc.) are allowed
+ "versionStrategy": "pin"
}`}
diff --git a/apps/docs/public/schema.json b/apps/docs/public/schema.json
index c28f207..70e1b65 100644
--- a/apps/docs/public/schema.json
+++ b/apps/docs/public/schema.json
@@ -25,6 +25,11 @@
},
"additionalProperties": false,
"description": "A mapping of dependencies and which workspaces are allowed to use different versions."
+ },
+ "versionStrategy": {
+ "type": "string",
+ "enum": ["pin", "loose"],
+ "description": "The versioning strategy to use across the repo, defaults to 'loose'."
}
},
"required": ["packageManager"],
diff --git a/packages/one-version/CHANGELOG.md b/packages/one-version/CHANGELOG.md
index d06a02f..73f5a0e 100644
--- a/packages/one-version/CHANGELOG.md
+++ b/packages/one-version/CHANGELOG.md
@@ -1,5 +1,21 @@
### Unreleased:
+### [0.2.0] - May 17th, 2024
+
+Added support for pinned version strategy checking.
+
+To enable, you can add `"versionStrategy": "pin"` to your `one-version.config.(json|jsonc)` configuration file:
+
+```jsonc
+{
+ "$schema": "https://one-version.vercel.app/schema.json",
+ "packageManager": "bun",
+ "versionStrategy": "pin"
+}
+```
+
+Notably, this respects your existing `overrides` configuration - if you want to allow some specific loose versions for specific dependencies.
+
### [0.1.1] - May 15th, 2024
- Added homepage to package.json, and repo info
diff --git a/packages/one-version/README.md b/packages/one-version/README.md
index f9c5d0b..6b4dbe4 100644
--- a/packages/one-version/README.md
+++ b/packages/one-version/README.md
@@ -28,6 +28,7 @@ Add a `one-version:check` script to your root `package.json`:
```jsonc
{
+ "$schema": "https://one-version.vercel.app/schema.json",
// one of: "bun", "yarn-berry", "yarn-classic", "pnpm", "npm"
// by default it will try to detect the package manager based on the presence of a lockfile
"packageManager": "bun",
@@ -35,9 +36,14 @@ Add a `one-version:check` script to your root `package.json`:
"overrides": {
"react": {
"18.0.0": ["pkg-a"],
- "17.0.0": ["pkg-b"]
+ // Wildcards are supported, and will capture any workspaces!
+ "17.0.0": ["*"]
}
- }
+ },
+ // one of: "pin", "loose", defaults to `loose` if not provided
+ // pin: all dependencies and devDependencies must use an exact version
+ // meaning no ranges (`^`, `~`, `.x`, etc.) are allowed
+ "versionStrategy": "pin"
}
```
@@ -51,10 +57,16 @@ Add a `one-version:check` script to your root `package.json`:
## Inspiration:
-This is effectively a fork of the [wayfair/one-version](https://github.com/wayfair/one-version) project, which I had partially contributed to while I was at Wayfair. This fork is intended to be a slimmer re-write of the original project, aiming to support the same functionality (eventually), with also supporting `bun`!
+This is effectively a fork of the [wayfair/one-version](https://github.com/wayfair/one-version) project, which I had partially contributed to while I was at Wayfair. This fork is intended to be a slimmer re-write of the original project, aiming to support the same functionality (eventually)!
This tool should be a drop-in replacement for `@wayfair/one-version`, if you run into any issues or collisions, please open an issue!
+This package also notably includes a few additional features:
+
+- Support for `npm` and `bun` package managers
+- Support for wildcards (`"*"`) within the `overrides` configuration
+- Support for `"versionStrategy"` configuration to enforce strict versioning across the repo!
+
## Contributing:
This library does not have a build step currently.
diff --git a/packages/one-version/__fixtures__/bun-configured-pinned/bun.lockb b/packages/one-version/__fixtures__/bun-configured-pinned/bun.lockb
new file mode 100755
index 0000000000000000000000000000000000000000..53bbd2ea3e19e7ca35f87e8dd8ffd883e475cb01
GIT binary patch
literal 4258
zcmds44NOy46n?FhN&NwtiYB7PZm@xU{S)o5W6nf}L&-$MOa({lYb}&lc<+^fGFLa9
zx+p6SMUy!-i%gg4#3>s8ahlCd;tvLh4#a4t)2WM2LsW3*w7u<{n@CZUWhc2k_wW1e
zx#ymH->EWM?c_PN$;PS~woqYmvT`UYyThDovDq1w#lhue3#vkmTuM>Y#;GOOYJXgA
zmM?cUvZszGg%470m94QJy#Drz%9yeVMG@gJ2}JHyRF6lr%hxuM3BEQ(<>y*eW@yDi
zfkD?0(4n9?Cfh7PeFv0Y(4Hvq_8;<%BhCbM)Y+hkL?3yrd2{5l)^#tthQ}{rO!Eeg
zzGqvUZgF33Y#!u3QZ8*Ma8fZmAU1nZ!;n)E=C=0x<2*nvb?Oj
zjlIKQxu=q3AG#lC+*hz<=yjCWp%?+*9kdJz>dpwk7sKSyfR6y(4N7PCMexS}qkjtg
z1Hg{~Jg$rOcUH*yQvsL=_+YTO2El&{c-%ksMT+{d-I0*(G@)6@VrO~
z!444A*avsSbCzfy`nD$&6x7&;JL8!b=F_13T!?>qzV@(oT1wKbpP%(Q3H|}{Io068oR@lk~C>z>_VFShmFe{-k%kn`ZZ0j{E$3#P%-uI!D>
znUe8F^->Y9_#Kf|#8(+}9=_X}yYjc{9tY2G&cO|%;$D%)$c#72N*gcDx;0jrxuW#I
z`w`6tW+n{jrc3E_{#s^wbm@pcQVPb!$(uyHB(BgGvT>)==TDP09o5GviwJCbKHgnJI@7Qzqt6e`dv?g!)bCN=1{k;F$lfy$N=GIjf
z^ECbud3CLbmwc&2^j)utc=3KdGXdVt3W*n@JB!14csI!R)@--Y
zIeaka=QB5mt$Pg!8t{DV{=cyX?N-Sq{4{~=^J%$}=ghQ?<%Mj!ohFGUoz5{#l0v6Z
z@V2>(!!lekLXmB^Sy_k0hoh+Whh9N8yjNFzBfWedJ-N}T*Che)F%)P!#x{NnF;VRc
z1$ppIK`Mif$JGfw#NnHPoOs9Z-A8VGPmvG%u#WE_YVjO#eVcEsg}q@Ch}<|sH!{;{
z09TCk??W4K1<7+seyZ?1v|zo9WWpqaRfOQ4$cP#0BqvsckZhD>*CZ<*Cea#bJ*}lE
zl7ExDIWR&pbdp&QlO)h1=mg*=ZwAS&rIIWyt)(>-bqGemV=j_q!-$5~>1iGHs0HDG
z@tW{>Hu4{U))b)7Gqw56r6Ud3J7PbEtik@}sHWRP*1f{=b^4H8B
zud8M|@`U1ihBtGze8Fpw*N8cSkk2Qo)f{8B@d8&&v-x>BJni7D>Ht8k5;atwSfd5&
z+zzn*RRQX+tGr=_P`ksyGb;GIYqJ#d<~hu4r=8)R#OLP<@N@tXF9Aq#Q>BILqCq>d
z^q@70k`hH0_Gof=mEg!_SiS>d{~TcT*Hs?)6TITzDIooImG>GV)N`Ew!JoeXTY|QD
literal 0
HcmV?d00001
diff --git a/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-a/package.json b/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-a/package.json
new file mode 100644
index 0000000..7f19605
--- /dev/null
+++ b/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-a/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "pkg-a",
+ "version": "0.0.0",
+ "dependencies": {
+ "react": "18.3.1",
+ "react-dom": "18.3.1"
+ },
+ "peerDependencies": {
+ "next": "14.3.0-canary.61"
+ },
+ "devDependencies": {
+ "typescript": "^5"
+ }
+}
diff --git a/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-b/package.json b/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-b/package.json
new file mode 100644
index 0000000..3a854a1
--- /dev/null
+++ b/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-b/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "pkg-b",
+ "version": "0.0.0",
+ "dependencies": {
+ "react": "18.3.1",
+ "react-dom": "18.3.1"
+ },
+ "peerDependencies": {
+ "next": "14.3.0-canary.61"
+ },
+ "devDependencies": {
+ "typescript": "^5.4"
+ }
+}
diff --git a/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-c/package.json b/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-c/package.json
new file mode 100644
index 0000000..336776b
--- /dev/null
+++ b/packages/one-version/__fixtures__/bun-configured-pinned/libs/pkg-c/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "pkg-c",
+ "version": "0.0.0",
+ "dependencies": {
+ "react": "18.3.1",
+ "react-dom": "18.3.1"
+ },
+ "peerDependencies": {
+ "next": "14.3.0-canary.61"
+ },
+ "devDependencies": {
+ "typescript": "5.4.5"
+ }
+}
diff --git a/packages/one-version/__fixtures__/bun-configured-pinned/one-version.config.jsonc b/packages/one-version/__fixtures__/bun-configured-pinned/one-version.config.jsonc
new file mode 100644
index 0000000..3bfc47d
--- /dev/null
+++ b/packages/one-version/__fixtures__/bun-configured-pinned/one-version.config.jsonc
@@ -0,0 +1,5 @@
+{
+ "$schema": "../../../../apps/docs/public/schema.json",
+ "packageManager": "bun",
+ "versionStrategy": "pin"
+}
diff --git a/packages/one-version/__fixtures__/bun-configured-pinned/package.json b/packages/one-version/__fixtures__/bun-configured-pinned/package.json
new file mode 100644
index 0000000..b591ff9
--- /dev/null
+++ b/packages/one-version/__fixtures__/bun-configured-pinned/package.json
@@ -0,0 +1,6 @@
+{
+ "private": true,
+ "workspaces": [
+ "libs/*"
+ ]
+}
diff --git a/packages/one-version/__tests__/one-version.test.mjs b/packages/one-version/__tests__/one-version.test.mjs
index 8d4ffc8..7e0b7ed 100644
--- a/packages/one-version/__tests__/one-version.test.mjs
+++ b/packages/one-version/__tests__/one-version.test.mjs
@@ -2,9 +2,9 @@ import assert from "node:assert";
import path from "node:path";
import { describe, test } from "node:test";
import { fileURLToPath } from "node:url";
-import { start } from "../one-version.mjs";
+import { getUnpinnedDependencies, start } from "../one-version.mjs";
-describe("one-version", () => {
+describe("one-version unit tests", () => {
test("supports help command", async () => {
let logs = [];
const logger = {
@@ -32,6 +32,104 @@ describe("one-version", () => {
assert.match(logs[0], /Unknown command:/);
});
+
+ describe("getUnpinnedDependencies", () => {
+ test("returns empty array when no dependencies are found", () => {
+ const workspaceDependencies = [{
+ name: "testing",
+ dependencies: {},
+ devDependencies: {},
+ peerDependencies: {},
+ }];
+ const result = getUnpinnedDependencies({ workspaceDependencies, overrides: undefined });
+
+ assert.deepEqual(result, {});
+ });
+
+ test("Covers the core edge cases", () => {
+ const workspaceDependencies = [{
+ name: "testing",
+ dependencies: {
+ foo: "^1.0.0",
+ },
+ devDependencies: {
+ bar: "2.0.x",
+ baz: "3.X",
+ react: "17.0.0 - 18.0.0",
+ "react-dom": "17.0.0 || 18.0.0",
+ "react-native": ">=0.64.0",
+ "react-native-web": "<0.17.0",
+ "one-version": "workspace:^*",
+ turbo: "workspace:~*",
+ next: "canary",
+ abc: "next",
+ def: "beta",
+ ghi: "alpha",
+ jkl: "rc",
+ mno: "dev",
+ // All below shouldn't show up!
+ hohoro: "workspace:*",
+ "react-router": "file:../react-router",
+ "left-pad": "git://github.com/jonschlinkert/left-pad.git#1.2.0",
+ "right-pad": "link:../right-pad",
+ "top-pad": "url:../top-pad",
+ },
+ peerDependencies: {
+ "peer-dep": "*",
+ },
+ }];
+ const result = getUnpinnedDependencies({ workspaceDependencies, overrides: undefined });
+
+ // peer-dep is omitted because it's a peer dependency
+ assert.deepEqual(result, {
+ testing: [
+ "foo@^1.0.0",
+ "bar@2.0.x",
+ "baz@3.X",
+ "react@17.0.0 - 18.0.0",
+ "react-dom@17.0.0 || 18.0.0",
+ "react-native@>=0.64.0",
+ "react-native-web@<0.17.0",
+ "one-version@workspace:^*",
+ "turbo@workspace:~*",
+ "next@canary",
+ "abc@next",
+ "def@beta",
+ "ghi@alpha",
+ "jkl@rc",
+ "mno@dev",
+ ],
+ });
+ });
+
+ test("Allows overriding dependencies", () => {
+ const workspaceDependencies = [{
+ name: "testing",
+ dependencies: {
+ foo: "^1.0.0",
+ },
+ devDependencies: {},
+ peerDependencies: {
+ next: "canary",
+ },
+ }];
+ const result = getUnpinnedDependencies({
+ workspaceDependencies,
+ overrides: {
+ next: {
+ canary: ["*"],
+ },
+ },
+ });
+
+ // Next not included because it's overridden
+ assert.deepEqual(result, {
+ testing: [
+ "foo@^1.0.0",
+ ],
+ });
+ });
+ });
});
let __filename = fileURLToPath(import.meta.url);
@@ -54,7 +152,6 @@ describe("one-version integration tests", () => {
// should fail - mismatch of typescript dependencies
assert.equal(statusCode, 1);
- assert.match(errors[0], /More than one version of dependencies found. See above output/);
// single log line with multiple new-lines
assert.match(logs[0], /One Version Rule Failure/);
assert.match(logs[0], /typescript/);
@@ -76,7 +173,6 @@ describe("one-version integration tests", () => {
// should fail - mismatch of typescript dependencies
assert.equal(statusCode, 1);
- assert.match(errors[0], /More than one version of dependencies found. See above output/);
// single log line with multiple new-lines
assert.match(logs[0], /One Version Rule Failure/);
assert.match(logs[0], /typescript/);
@@ -98,7 +194,6 @@ describe("one-version integration tests", () => {
// should fail - mismatch of typescript dependencies
assert.equal(statusCode, 1);
- assert.match(errors[0], /More than one version of dependencies found. See above output/);
// single log line with multiple new-lines
assert.match(logs[0], /One Version Rule Failure/);
assert.match(logs[0], /typescript/);
@@ -120,7 +215,6 @@ describe("one-version integration tests", () => {
// should fail - mismatch of typescript dependencies
assert.equal(statusCode, 1);
- assert.match(errors[0], /More than one version of dependencies found. See above output/);
// single log line with multiple new-lines
assert.match(logs[0], /One Version Rule Failure/);
assert.match(logs[0], /typescript/);
@@ -142,7 +236,6 @@ describe("one-version integration tests", () => {
// should fail - mismatch of typescript dependencies
assert.equal(statusCode, 1);
- assert.match(errors[0], /More than one version of dependencies found. See above output/);
// single log line with multiple new-lines
assert.match(logs[0], /One Version Rule Failure/);
assert.match(logs[0], /typescript/);
@@ -188,4 +281,25 @@ describe("one-version integration tests", () => {
// single log line with multiple new-lines
assert.match(logs[0], /One Version Rule Success/);
});
+
+ test("bun - configured and pinned versions", async () => {
+ const targetDir = path.join(__dirname, "..", "__fixtures__", "bun-configured-pinned");
+ let logs = [];
+ let errors = [];
+ let logger = {
+ log(...args) {
+ logs.push(args.join(" "));
+ },
+ error(...args) {
+ errors.push(args.join(" "));
+ },
+ };
+ let { statusCode } = await start({ rootDirectory: targetDir, logger, args: ["check"] });
+
+ // should fail because of loose deps
+ assert.equal(statusCode, 1);
+
+ assert.equal(logs.length, 2);
+ assert.match(logs[0], /One Version Rule Failure/);
+ });
});
diff --git a/packages/one-version/one-version.mjs b/packages/one-version/one-version.mjs
index cbac510..c23ae2e 100644
--- a/packages/one-version/one-version.mjs
+++ b/packages/one-version/one-version.mjs
@@ -15,10 +15,12 @@ let debug = createDebug("one-version");
* @typedef {string} WorkspaceName - Name of workspace, e.g. "one-version"
* @typedef {'yarn-classic' | 'yarn-berry' | 'npm' | 'pnpm' | 'bun'} PackageManager
* @typedef {Record>} Overrides
+ * @typedef {'pin' | 'loose'} VersionStrategy
*
* @typedef {object} Config
* @property {PackageManager} packageManager
* @property {Overrides} overrides
+ * @property {VersionStrategy} versionStrategy
*/
/**
@@ -306,7 +308,9 @@ function getDuplicateDependencies({ workspaceDependencies, overrides }) {
let filteredVersions = Object.entries(versions)
.map(([version, { direct, peer, dev }]) => {
let filteredPackages = {};
- let notOverridden = (packageName) => !packageOverrides[version]?.includes(packageName);
+ let notOverridden = (packageName) =>
+ // If it's not a direct match on the packageName (workspaceName) and if it's not a wildcard match
+ !packageOverrides[version]?.includes(packageName) && !packageOverrides[version]?.includes("*");
if (direct) {
let directDependencies = direct.filter(notOverridden);
if (directDependencies.length > 0) {
@@ -382,6 +386,73 @@ function prettify(packages) {
.join("\n");
}
+// MARK: Get Unpinned Dependencies
+
+/**
+ * @param {object} options
+ * @param {Array} options.workspaceDependencies
+ * @param {Overrides} options.overrides
+ * @returns {Record>}
+ *
+ * exported for tests only
+ */
+export function getUnpinnedDependencies({ workspaceDependencies, overrides }) {
+ let unpinnedDependencies = {};
+ // Notably - omit peerDeps since those can be semver ranges
+ for (let { name: workspaceName, dependencies, devDependencies } of workspaceDependencies) {
+ let allDependencies = { ...dependencies, ...devDependencies };
+ for (let [packageName, version] of Object.entries(allDependencies)) {
+ // Let `file:`, `url:`, `git:`, `link:`, and `workspace:*` dependencies pass currently
+ if (
+ version.startsWith("file:")
+ || version.startsWith("url:")
+ || version.startsWith("git:")
+ || version.startsWith("link:")
+ || version === "workspace:*"
+ ) {
+ continue;
+ }
+ if (
+ version.startsWith("^")
+ || version.startsWith("~")
+ // any version
+ || version.includes("*")
+ // range versions
+ || version.includes(".x")
+ || version.includes(".X")
+ || version.includes(" - ")
+ || version.includes(" || ")
+ // Greater Than, Less Than
+ || version.includes(">")
+ || version.includes("<")
+ // Keywords:
+ || version === "latest"
+ || version === "canary"
+ || version === "next"
+ || version === "beta"
+ || version === "alpha"
+ || version === "rc"
+ || version === "dev"
+ // workspace custom semver range deps
+ || version.startsWith("workspace:^")
+ || version.startsWith("workspace:~")
+ ) {
+ if (
+ // If we've overridden this specific package@version for this specific workspace
+ overrides?.[packageName]?.[version]?.includes(workspaceName)
+ // or if we've overridden this specific package@version for any workspace
+ || overrides?.[packageName]?.[version]?.includes("*")
+ ) {
+ continue;
+ }
+ unpinnedDependencies[workspaceName] = unpinnedDependencies[workspaceName] || [];
+ unpinnedDependencies[workspaceName].push(`${packageName}@${version}`);
+ }
+ }
+ }
+ return unpinnedDependencies;
+}
+
// MARK: Start
let usageLogs = [
"",
@@ -399,7 +470,7 @@ let usageLogs = [
* @param {Array} options.args
* @param {Function} options.exit
*/
-export async function start({ rootDirectory, logger, args, exit }) {
+export async function start({ rootDirectory, logger, args }) {
let [firstArg] = args;
switch (firstArg) {
@@ -415,6 +486,9 @@ export async function start({ rootDirectory, logger, args, exit }) {
}
initialConfig.packageManager = inferredPackageManager;
}
+ if (!initialConfig.versionStrategy) {
+ initialConfig.versionStrategy = "loose";
+ }
debug("Initial config", JSON.stringify(initialConfig, null, 2));
let workspaces = getWorkspaces({ rootDirectory, packageManager: initialConfig.packageManager });
debug("Workspaces", JSON.stringify(workspaces, null, 2));
@@ -422,31 +496,56 @@ export async function start({ rootDirectory, logger, args, exit }) {
let workspaceDependencies = workspaces.map(({ path }) => getDependencies({ path }));
debug("Workspaces Dependencies", JSON.stringify(workspaceDependencies, null, 2));
+ // Check for duplicate and mismatched versions of dependencies
let duplicateDependencies = getDuplicateDependencies({
workspaceDependencies,
overrides: initialConfig.overrides,
});
debug("Duplicate dependencies", JSON.stringify(duplicateDependencies, null, 2));
+ let pendingStatusCode = 0;
+ let status = "✅";
+
if (duplicateDependencies.length > 0) {
+ status = "🚫";
logger.log(
"You shall not pass!\n",
"🚫 One Version Rule Failure - found multiple versions of the following dependencies:\n",
prettify(duplicateDependencies),
);
- logger.error("More than one version of dependencies found. See above output.");
- return Promise.resolve({
- statusCode: 1,
+ pendingStatusCode = 1;
+ }
+
+ // check versionStrategy
+ if (initialConfig.versionStrategy === "pin") {
+ // check if all dependencies are pinned
+ let unpinnedDependencies = getUnpinnedDependencies({
+ workspaceDependencies,
+ overrides: initialConfig.overrides,
});
+ debug("Unpinned dependencies", JSON.stringify(unpinnedDependencies, null, 2));
+
+ if (Object.keys(unpinnedDependencies).length > 0) {
+ status = "🚫";
+ logger.log(
+ "🚫 One Version Rule Failure - found unpinned dependencies (with versionStrategy: 'pin'):\n",
+ Object.entries(unpinnedDependencies).map(([workspaceName, deps]) => {
+ return `${workspaceName}:\n- ${deps.join("\n -")}`;
+ }).join("\n\n"),
+ );
+ pendingStatusCode = 1;
+ }
}
- logger.log(
- "My preciousss\n",
- "✨ One Version Rule Success - found no version conflicts!",
- );
+ if (status === "✅") {
+ logger.log(
+ "My preciousss\n",
+ "✨ One Version Rule Success - found no version conflicts!",
+ );
+ }
return Promise.resolve({
- statusCode: 0,
+ statusCode: pendingStatusCode,
});
}
case "help": {
diff --git a/packages/one-version/package.json b/packages/one-version/package.json
index 65a07b7..87a0434 100644
--- a/packages/one-version/package.json
+++ b/packages/one-version/package.json
@@ -1,6 +1,6 @@
{
"name": "one-version",
- "version": "0.1.1",
+ "version": "0.2.0",
"homepage": "https://one-version.vercel.app/",
"description": "A strict dependency conformance tool for (mono)repos!",
"repository": {