From ee19caf01ed4c56bb15055edfa5029086f6d7f59 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Fri, 9 Feb 2024 11:58:24 -0800 Subject: [PATCH 1/3] feat(laverna): automatic support for CI If the `CI` env var is `true`, `--yes` will be the default behavior so that it does not attempt to read from STDIN. --- packages/laverna/README.md | 31 +++++++++++++++++++------------ packages/laverna/package.json | 4 ++-- packages/laverna/src/cli.js | 18 ++++++++++-------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/laverna/README.md b/packages/laverna/README.md index dada7bc3fb..c2511f832a 100644 --- a/packages/laverna/README.md +++ b/packages/laverna/README.md @@ -4,18 +4,20 @@ If you're familiar with [lerna](https://lerna.js.org), **Laverna** does this: `lerna publish from-package`. -If you're unfamiliar with it: **Laverna** publishes all workspaces that haven't yet been published. +If you're unfamiliar with it: **Laverna** publishes all workspacess wherein the _current_ version hasn't yet been published. ## Features **Laverna** is a thin wrapper around `npm publish` which: -- Invokes `npm publish` for all workspaces _that haven't yet been published_ -- Handles new packages (via a flag) +- Invokes `npm publish` on _all_ workspaces _where the current version has not yet been published_ +- Publishes new packages via flag - Ignores private packages -- Requires a confirmation (by default) +- Requires confirmation (by default) +- Prints all output from `npm publish`, including the output of `npm pack`, to enable review prior to confirmation - Provides a "dry-run" mode -- Prints all output from `npm publish`, including the output of `npm pack`, to enable review + +**Laverna**'s scope is intentionally limited to the above use-case. ## Non-Features @@ -23,10 +25,12 @@ Perhaps more importantly, **Laverna**: - Builds nothing - Bumps no versions -- Does not write to `package.json` +- Runs no user-defined scripts +- Retains no state nor cache +- Does not write to `package.json` or lockfiles - Does not interact with `git` (no tags, no commits, no pushes) - Does not interact with GitHub (no releases) -- Does not cache anything +- Avails no whims ## Supported Environments @@ -46,16 +50,16 @@ npm install @lavamoat/laverna -D ```plain laverna [options..] -Publish multiple workspaces (that's all) +"Publish multiple workspaces (that's all)" Options: --dryRun - Enable dry-run mode --root= - Path to workspace root (default: current working dir) - --newPkg= - Workspace has never been published (repeatable) - --yes/-y - Skip confirmation prompt + --newPkg= - Workspace should be treated as a new package (repeatable) + --yes/-y - Skip confirmation prompt (default: false; true in CI) -Problems? Visit https://github.com/LavaMoat/lavamoat/issues +Problems? Visit https://github.com/LavaMoat/LavaMoat/issues ``` ## Examples @@ -78,7 +82,10 @@ If you're publishing a package in a new workspace, you might: ### Automating Publishes -You'll need to figure out how to add `--newPkg` to your CI/CD pipeline. Otherwise, use the `--yes` flag when invoking `laverna`. +If the `CI` environment variable is present, `laverna` will skip the confirmation prompt before final publish (i.e., `--yes` defaults to `true`). + +> [!WARNING] +> Publishing via CI can bypass 2FA protections. Use at your own risk! ## API diff --git a/packages/laverna/package.json b/packages/laverna/package.json index fbadf6c66a..86028e7388 100644 --- a/packages/laverna/package.json +++ b/packages/laverna/package.json @@ -4,12 +4,12 @@ "description": "Publish multiple workspaces (that's all)", "repository": { "type": "git", - "url": "git+https://github.com/LavaMoat/lavamoat.git", + "url": "git+https://github.com/LavaMoat/LavaMoat.git", "directory": "packages/laverna" }, "homepage": "https://github.com/LavaMoat/LavaMoat/blob/main/packages/laverna/README.md", "bugs": { - "url": "https://github.com/LavaMoat/lavamoat/issues" + "url": "https://github.com/LavaMoat/LavaMoat/issues" }, "author": "boneskull", "license": "MIT", diff --git a/packages/laverna/src/cli.js b/packages/laverna/src/cli.js index 1231073cc5..9dbfe20658 100755 --- a/packages/laverna/src/cli.js +++ b/packages/laverna/src/cli.js @@ -3,7 +3,7 @@ /* eslint-disable n/shebang */ // @ts-check -const { bold, magenta, gray, italic } = require('kleur') +const { bold, magenta, gray, italic, cyan, underline } = require('kleur') const util = require('node:util') const { Laverna } = require('./laverna') const { ERR } = require('./log-symbols') @@ -72,18 +72,18 @@ function main() { // this should be the only place we write to stdout unless we // want to start outputting JSON console.log(` - ${bold('laverna')} [options..] + ${cyan(bold('laverna'))} ${cyan('[options..]')} - ${italic(description)} + "${description}" Options: - --dryRun - Enable dry-run mode - --root= - Path to workspace root (default: current working dir) - --newPkg= - Workspace has never been published (repeatable) - --yes/-y - Skip confirmation prompt + ${bold('--dryRun')} - Enable dry-run mode + ${bold('--root=')} - Path to workspace root (default: current working dir) + ${bold('--newPkg=')} - Workspace should be treated as a new package (repeatable) + ${bold('--yes/-y')} - Skip confirmation prompt (default: false; true ${italic('in CI')}) - Problems? Visit ${bugs.url} + Problems? Visit ${underline(bugs.url)} `) } else { @@ -92,6 +92,8 @@ function main() { opts.newPkg = [ ...new Set([...(opts.newPkg ?? []), ...(opts['new-pkg'] ?? [])]), ] + // must be true in CI; --yes=false is not a thing + opts.yes = Boolean(process.env.CI) || opts.yes console.error(`📦 ${bold(magenta(name)) + gray('@') + magenta(version)}\n`) const laverna = new Laverna(opts) From 869a8c54f4c54ccbd733fe68c5b6d0e74182761f Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Fri, 9 Feb 2024 12:05:36 -0800 Subject: [PATCH 2/3] fix(laverna): update type-fest --- package-lock.json | 111 ++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14a36501e6..fc44ed1fce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -349,9 +349,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.0.tgz", - "integrity": "sha512-efwOM90nCG6YeT8o3PCyBVSxRfmILxCNL+TNI8CGQl7a62M0Wd9VkV+XHwIlkOz1r4b+lxu6gBjdWiOMdUCrCQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -2478,13 +2478,13 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -2898,9 +2898,9 @@ } }, "node_modules/@types/lodash": { - "version": "4.14.202", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", + "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==" }, "node_modules/@types/mdast": { "version": "4.0.3", @@ -5156,13 +5156,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.9.tgz", - "integrity": "sha512-BXIWIaO3MewbXWdJdIGDWZurv5OGJlFNo7oy20DpB3kWDVJLcY2NRypRsRUbRe5KMqSNLuOGnWTFQQtY5MAsRw==", + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.0", + "@babel/helper-define-polyfill-provider": "^0.6.1", "semver": "^6.3.1" }, "peerDependencies": { @@ -6095,9 +6095,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001596", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001596.tgz", - "integrity": "sha512-zpkZ+kEr6We7w63ORkoJ2pOfBwBkY/bJrG/UZ90qNb45Isblu8wzDgevEOrRL1r9dWayHjYiiyCMEXPn4DweGQ==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true, "funding": [ { @@ -7975,9 +7975,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.699", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.699.tgz", - "integrity": "sha512-I7q3BbQi6e4tJJN5CRcyvxhK0iJb34TV8eJQcgh+fR2fQ8miMgZcEInckCo1U9exDHbfz7DLDnFn8oqH/VcRKw==", + "version": "1.4.702", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.702.tgz", + "integrity": "sha512-LYLXyEUsZ3nNSwiOWjI88N1PJUAMU2QphQSgGLVkFnb3FxZxNui2Vzi2PaKPgPWbsWbZstZnh6BMf/VQJamjiQ==", "dev": true }, "node_modules/elliptic": { @@ -8046,9 +8046,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz", - "integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -10038,9 +10038,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -15421,13 +15421,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -15675,16 +15675,16 @@ } }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -17071,9 +17071,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { "node": ">=16" @@ -17862,30 +17862,33 @@ } }, "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" From c4984aa511500abba34a17d33c8c70819d874110 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Fri, 9 Feb 2024 14:21:57 -0800 Subject: [PATCH 3/3] chore(laverna): update snapshots --- packages/laverna/test/snapshots/cli.spec.js.md | 8 ++++---- .../laverna/test/snapshots/cli.spec.js.snap | Bin 377 -> 406 bytes 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/laverna/test/snapshots/cli.spec.js.md b/packages/laverna/test/snapshots/cli.spec.js.md index e389eff06b..b5f5334072 100644 --- a/packages/laverna/test/snapshots/cli.spec.js.md +++ b/packages/laverna/test/snapshots/cli.spec.js.md @@ -11,16 +11,16 @@ Generated by [AVA](https://avajs.dev). `␊ laverna [options..]␊ ␊ - Publish multiple workspaces (that's all)␊ + "Publish multiple workspaces (that's all)"␊ ␊ Options:␊ ␊ --dryRun - Enable dry-run mode␊ --root= - Path to workspace root (default: current working dir)␊ - --newPkg= - Workspace has never been published (repeatable)␊ - --yes/-y - Skip confirmation prompt␊ + --newPkg= - Workspace should be treated as a new package (repeatable)␊ + --yes/-y - Skip confirmation prompt (default: false; true in CI)␊ ␊ - Problems? Visit https://github.com/LavaMoat/lavamoat/issues␊ + Problems? Visit https://github.com/LavaMoat/LavaMoat/issues␊ ␊ ␊ ` diff --git a/packages/laverna/test/snapshots/cli.spec.js.snap b/packages/laverna/test/snapshots/cli.spec.js.snap index f7f3585aa857e69240be0b528e49c66a5f1e7bc0..87e5e46a58223d9a0bde120e1d0b1dd8c90835c5 100644 GIT binary patch literal 406 zcmV;H0crk0RzVzKO#Nr+Fse(A8PeQa9UKeIaZ{M2}d3Mspw0?R%*36#V} zmHojOQu;G|{W$nM=r#N_xcKlg908s-oCD!8CUr5$bozHR0xp-O_D(Fi;?*V3*v8yS zqJ{-ywWMDJHO?ND_YIi>4XX_H07*;NK)ZdGgW0(F9xFRq76`Bjf1>An0 z^dDK~SbOf|2EUv*g;h;5pUu`zZK}Gegp&ya-TsV=!(vOec0K)a(?dt&m065Ub ATmS$7 literal 377 zcmV-<0fzoTRzVJZpaEAnvmK zXwPJxQXh*5000000009;P(4oqQ4j=;F`@GxY$p`Q^%ua(P9xDoV~oY#-NJjh_vPC? z2!#c`e*%B0?+zkcZ6-6bvvXLL##asRe@V0$`l^hE3_{dS7!;YH*|%K8W^?r_;|-f|qS+G%K*J5giP{*2jheR>UwCg>uV) z#!Ncy(@|M;dzRI4_uM)-O$PT4%cM_m787oLO+7DqFY{SIQH!3pOdE(lAA*hnpxqj39Vfk$qwTU;&u0!TEt1pQzrzVq$lxgb2_=z(aQuyG7)J_}nn?kV zRy*Q6+nvL|G&(@#-AYG`-Iu9gZ-ev|MW1w*@8DIl7EmIAi#%UzQEfS`yv-kQgO461 XPc5VE7R}reck