From 7358d2acca2a54df603c98df5f96a09447e883bf Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Fri, 9 Feb 2024 11:58:24 -0800 Subject: [PATCH] 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)