Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Fritz <fritzy@github.com>2021-12-16 21:01:56 +0300
committerNathan Fritz <fritzy@github.com>2021-12-16 21:05:19 +0300
commitd7265045730555c03b3142c004c7438e9577028c (patch)
tree035d81b3124bdaa09c21854934bf2b2b50e52e44 /workspaces/libnpmversion
parentd8aac8448e983692cacb427e03f4688cd1b62e30 (diff)
Bring in all libnpm modules + arborist as workspaces (#4166)
Added libnpm workspaces and arborist
Diffstat (limited to 'workspaces/libnpmversion')
-rw-r--r--workspaces/libnpmversion/.eslintrc.js14
-rw-r--r--workspaces/libnpmversion/.gitignore23
-rw-r--r--workspaces/libnpmversion/.npmrc3
-rw-r--r--workspaces/libnpmversion/LICENSE15
-rw-r--r--workspaces/libnpmversion/README.md159
-rw-r--r--workspaces/libnpmversion/SECURITY.md3
-rw-r--r--workspaces/libnpmversion/lib/commit.js17
-rw-r--r--workspaces/libnpmversion/lib/enforce-clean.js31
-rw-r--r--workspaces/libnpmversion/lib/index.js41
-rw-r--r--workspaces/libnpmversion/lib/proc-log.js21
-rw-r--r--workspaces/libnpmversion/lib/read-json.js7
-rw-r--r--workspaces/libnpmversion/lib/retrieve-tag.js13
-rw-r--r--workspaces/libnpmversion/lib/tag.js30
-rw-r--r--workspaces/libnpmversion/lib/version.js137
-rw-r--r--workspaces/libnpmversion/lib/write-json.js16
-rw-r--r--workspaces/libnpmversion/map.js1
-rw-r--r--workspaces/libnpmversion/package.json48
-rw-r--r--workspaces/libnpmversion/tap-snapshots/test/commit.js.test.cjs23
-rw-r--r--workspaces/libnpmversion/tap-snapshots/test/index.js.test.cjs66
-rw-r--r--workspaces/libnpmversion/tap-snapshots/test/read-json.js.test.cjs28
-rw-r--r--workspaces/libnpmversion/tap-snapshots/test/tag.js.test.cjs22
-rw-r--r--workspaces/libnpmversion/test/commit.js17
-rw-r--r--workspaces/libnpmversion/test/enforce-clean.js68
-rw-r--r--workspaces/libnpmversion/test/index.js39
-rw-r--r--workspaces/libnpmversion/test/proc-log.js11
-rw-r--r--workspaces/libnpmversion/test/read-json.js37
-rw-r--r--workspaces/libnpmversion/test/retrieve-tag.js20
-rw-r--r--workspaces/libnpmversion/test/tag.js16
-rw-r--r--workspaces/libnpmversion/test/version.js368
-rw-r--r--workspaces/libnpmversion/test/write-json.js60
30 files changed, 1354 insertions, 0 deletions
diff --git a/workspaces/libnpmversion/.eslintrc.js b/workspaces/libnpmversion/.eslintrc.js
new file mode 100644
index 000000000..022767bc3
--- /dev/null
+++ b/workspaces/libnpmversion/.eslintrc.js
@@ -0,0 +1,14 @@
+// This file is automatically added by @npmcli/template-oss. Do not edit.
+
+const { readdirSync: readdir } = require('fs')
+
+const localConfigs = readdir(__dirname)
+ .filter((file) => file.startsWith('.eslintrc.local.'))
+ .map((file) => `./${file}`)
+
+module.exports = {
+ extends: [
+ '@npmcli',
+ ...localConfigs,
+ ],
+}
diff --git a/workspaces/libnpmversion/.gitignore b/workspaces/libnpmversion/.gitignore
new file mode 100644
index 000000000..6ed44c72b
--- /dev/null
+++ b/workspaces/libnpmversion/.gitignore
@@ -0,0 +1,23 @@
+# This file is automatically added by @npmcli/template-oss. Do not edit.
+
+# ignore everything in the root
+/*
+
+# keep these
+!/.commitlintrc.js
+!/.npmrc
+!/.eslintrc*
+!/.github
+!**/.gitignore
+!/package.json
+!/docs
+!/bin
+!/lib
+!/map.js
+!/tap-snapshots
+!/test
+!/scripts
+!/README*
+!/LICENSE*
+!/SECURITY*
+!/CHANGELOG*
diff --git a/workspaces/libnpmversion/.npmrc b/workspaces/libnpmversion/.npmrc
new file mode 100644
index 000000000..878b7ddef
--- /dev/null
+++ b/workspaces/libnpmversion/.npmrc
@@ -0,0 +1,3 @@
+;This file is automatically added by @npmcli/template-oss. Do not edit.
+
+package-lock=false
diff --git a/workspaces/libnpmversion/LICENSE b/workspaces/libnpmversion/LICENSE
new file mode 100644
index 000000000..05eeeb88c
--- /dev/null
+++ b/workspaces/libnpmversion/LICENSE
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/workspaces/libnpmversion/README.md b/workspaces/libnpmversion/README.md
new file mode 100644
index 000000000..e82e7cd6f
--- /dev/null
+++ b/workspaces/libnpmversion/README.md
@@ -0,0 +1,159 @@
+# libnpmversion
+
+Library to do the things that 'npm version' does.
+
+## USAGE
+
+```js
+const npmVersion = require('libnpmversion')
+
+// argument can be one of:
+// - any semver version string (set to that exact version)
+// - 'major', 'minor', 'patch', 'pre{major,minor,patch}' (increment at
+// that value)
+// - 'from-git' (set to the latest semver-lookin git tag - this skips
+// gitTagVersion, but will still sign if asked)
+npmVersion(arg, {
+ path: '/path/to/my/pkg', // defaults to cwd
+
+ allowSameVersion: false, // allow tagging/etc to the current version
+ preid: '', // when arg=='pre', define the prerelease string, like 'beta' etc.
+ tagVersionPrefix: 'v', // tag as 'v1.2.3' when versioning to 1.2.3
+ commitHooks: true, // default true, run git commit hooks, default true
+ gitTagVersion: true, // default true, tag the version
+ signGitCommit: false, // default false, gpg sign the git commit
+ signGitTag: false, // default false, gpg sign the git tag
+ force: false, // push forward recklessly if any problems happen
+ ignoreScripts: false, // do not run pre/post/version lifecycle scripts
+ scriptShell: '/bin/bash', // shell to run lifecycle scripts in
+ message: 'v%s', // message for tag and commit, replace %s with the version
+}).then(newVersion => {
+ console.error('version updated!', newVersion)
+})
+```
+
+## Description
+
+Run this in a package directory to bump the version and write the new data
+back to `package.json`, `package-lock.json`, and, if present,
+`npm-shrinkwrap.json`.
+
+The `newversion` argument should be a valid semver string, a valid second
+argument to [semver.inc](https://github.com/npm/node-semver#functions) (one
+of `patch`, `minor`, `major`, `prepatch`, `preminor`, `premajor`,
+`prerelease`), or `from-git`. In the second case, the existing version will
+be incremented by 1 in the specified field. `from-git` will try to read
+the latest git tag, and use that as the new npm version.
+
+If run in a git repo, it will also create a version commit and tag. This
+behavior is controlled by `gitTagVersion` (see below), and can be
+disabled by setting `gitTagVersion: false` in the options.
+It will fail if the working directory is not clean, unless `force: true` is
+set.
+
+If supplied with a `message` string option, it will
+use it as a commit message when creating a version commit. If the
+`message` option contains `%s` then that will be replaced with the
+resulting version number.
+
+If the `signGitTag` option is set, then the tag will be signed using
+the `-s` flag to git. Note that you must have a default GPG key set up in
+your git config for this to work properly.
+
+If `preversion`, `version`, or `postversion` are in the `scripts` property
+of the package.json, they will be executed in the appropriate sequence.
+
+The exact order of execution is as follows:
+
+1. Check to make sure the git working directory is clean before we get
+ started. Your scripts may add files to the commit in future steps.
+ This step is skipped if the `force` flag is set.
+2. Run the `preversion` script. These scripts have access to the old
+ `version` in package.json. A typical use would be running your full
+ test suite before deploying. Any files you want added to the commit
+ should be explicitly added using `git add`.
+3. Bump `version` in `package.json` as requested (`patch`, `minor`,
+ `major`, explicit version number, etc).
+4. Run the `version` script. These scripts have access to the new `version`
+ in package.json (so they can incorporate it into file headers in
+ generated files for example). Again, scripts should explicitly add
+ generated files to the commit using `git add`.
+5. Commit and tag.
+6. Run the `postversion` script. Use it to clean up the file system or
+ automatically push the commit and/or tag.
+
+Take the following example:
+
+```json
+{
+ "scripts": {
+ "preversion": "npm test",
+ "version": "npm run build && git add -A dist",
+ "postversion": "git push && git push --tags && rm -rf build/temp"
+ }
+}
+```
+
+This runs all your tests, and proceeds only if they pass. Then runs your
+`build` script, and adds everything in the `dist` directory to the commit.
+After the commit, it pushes the new commit and tag up to the server, and
+deletes the `build/temp` directory.
+
+## API
+
+### `npmVersion(newversion, options = {}) -> Promise<String>`
+
+Do the things. Returns a promise that resolves to the new version if
+all is well, or rejects if any errors are encountered.
+
+### Options
+
+#### `path` String
+
+The path to the package being versionified. Defaults to process.cwd().
+
+#### `allowSameVersion` Boolean
+
+Allow setting the version to the current version in package.json. Default
+`false`.
+
+#### `preid` String
+When the `newversion` is pre, premajor, preminor, or prepatch, this
+defines the prerelease string, like 'beta' etc.
+
+#### `tagVersionPrefix` String
+
+The prefix to add to the raw semver string for the tag name. Defaults to
+`'v'`. (So, by default it tags as 'v1.2.3' when versioning to 1.2.3.)
+
+#### `commitHooks` Boolean
+
+Run git commit hooks. Default true.
+
+#### `gitTagVersion` Boolean
+
+Tag the version, default true.
+
+#### `signGitCommit` Boolean
+
+GPG sign the git commit. Default `false`.
+
+#### `signGitTag` Boolean
+
+GPG sign the git tag. Default `false`.
+
+#### `force` Boolean
+
+Push forward recklessly if any problems happen. Default `false`.
+
+#### `ignoreScripts` Boolean
+
+Do not run pre/post/version lifecycle scripts. Default `false`.
+
+#### `scriptShell` String
+
+Path to the shell, which should execute the lifecycle scripts. Defaults to `/bin/sh` on unix, or `cmd.exe` on windows.
+
+#### `message` String
+
+The message for the git commit and annotated git tag that are created.
diff --git a/workspaces/libnpmversion/SECURITY.md b/workspaces/libnpmversion/SECURITY.md
new file mode 100644
index 000000000..a93106d0c
--- /dev/null
+++ b/workspaces/libnpmversion/SECURITY.md
@@ -0,0 +1,3 @@
+<!-- This file is automatically added by @npmcli/template-oss. Do not edit. -->
+
+Please send vulnerability reports through [hackerone](https://hackerone.com/github).
diff --git a/workspaces/libnpmversion/lib/commit.js b/workspaces/libnpmversion/lib/commit.js
new file mode 100644
index 000000000..dec6edbec
--- /dev/null
+++ b/workspaces/libnpmversion/lib/commit.js
@@ -0,0 +1,17 @@
+const git = require('@npmcli/git')
+
+module.exports = (version, opts) => {
+ const { commitHooks, allowSameVersion, signGitCommit, message } = opts
+ const args = ['commit']
+ if (commitHooks === false) {
+ args.push('-n')
+ }
+ if (allowSameVersion) {
+ args.push('--allow-empty')
+ }
+ if (signGitCommit) {
+ args.push('-S')
+ }
+ args.push('-m')
+ return git.spawn([...args, message.replace(/%s/g, version)], opts)
+}
diff --git a/workspaces/libnpmversion/lib/enforce-clean.js b/workspaces/libnpmversion/lib/enforce-clean.js
new file mode 100644
index 000000000..6103da9bd
--- /dev/null
+++ b/workspaces/libnpmversion/lib/enforce-clean.js
@@ -0,0 +1,31 @@
+const git = require('@npmcli/git')
+
+// returns true if it's cool to do git stuff
+// throws if it's unclean, and not forced.
+module.exports = async opts => {
+ const { force, log } = opts
+ let hadError = false
+ const clean = await git.isClean(opts).catch(er => {
+ if (er.code === 'ENOGIT') {
+ log.warn(
+ 'version',
+ 'This is a Git checkout, but the git command was not found.',
+ 'npm could not create a Git tag for this release!'
+ )
+ hadError = true
+ // how can merges be real if our git isn't real?
+ return true
+ } else {
+ throw er
+ }
+ })
+
+ if (!clean) {
+ if (!force) {
+ throw new Error('Git working directory not clean.')
+ }
+ log.warn('version', 'Git working directory not clean, proceeding forcefully.')
+ }
+
+ return !hadError
+}
diff --git a/workspaces/libnpmversion/lib/index.js b/workspaces/libnpmversion/lib/index.js
new file mode 100644
index 000000000..683941cde
--- /dev/null
+++ b/workspaces/libnpmversion/lib/index.js
@@ -0,0 +1,41 @@
+const readJson = require('./read-json.js')
+const version = require('./version.js')
+const proclog = require('./proc-log.js')
+
+module.exports = async (newversion, opts = {}) => {
+ const {
+ path = process.cwd(),
+ allowSameVersion = false,
+ tagVersionPrefix = 'v',
+ commitHooks = true,
+ gitTagVersion = true,
+ signGitCommit = false,
+ signGitTag = false,
+ force = false,
+ ignoreScripts = false,
+ scriptShell = undefined,
+ preid = null,
+ log = proclog,
+ message = 'v%s',
+ } = opts
+
+ const pkg = opts.pkg || await readJson(path + '/package.json')
+
+ return version(newversion, {
+ path,
+ cwd: path,
+ allowSameVersion,
+ tagVersionPrefix,
+ commitHooks,
+ gitTagVersion,
+ signGitCommit,
+ signGitTag,
+ force,
+ ignoreScripts,
+ scriptShell,
+ preid,
+ pkg,
+ log,
+ message,
+ })
+}
diff --git a/workspaces/libnpmversion/lib/proc-log.js b/workspaces/libnpmversion/lib/proc-log.js
new file mode 100644
index 000000000..a7c683ba2
--- /dev/null
+++ b/workspaces/libnpmversion/lib/proc-log.js
@@ -0,0 +1,21 @@
+// default logger.
+// emits 'log' events on the process
+const LEVELS = [
+ 'notice',
+ 'error',
+ 'warn',
+ 'info',
+ 'verbose',
+ 'http',
+ 'silly',
+ 'pause',
+ 'resume',
+]
+
+const log = level => (...args) => process.emit('log', level, ...args)
+
+const logger = {}
+for (const level of LEVELS) {
+ logger[level] = log(level)
+}
+module.exports = logger
diff --git a/workspaces/libnpmversion/lib/read-json.js b/workspaces/libnpmversion/lib/read-json.js
new file mode 100644
index 000000000..2dd0f7aa4
--- /dev/null
+++ b/workspaces/libnpmversion/lib/read-json.js
@@ -0,0 +1,7 @@
+// can't use read-package-json-fast, because we want to ensure
+// that we make as few changes as possible, even for safety issues.
+const { promisify } = require('util')
+const readFile = promisify(require('fs').readFile)
+const parse = require('json-parse-even-better-errors')
+
+module.exports = async path => parse(await readFile(path))
diff --git a/workspaces/libnpmversion/lib/retrieve-tag.js b/workspaces/libnpmversion/lib/retrieve-tag.js
new file mode 100644
index 000000000..c5fb64e33
--- /dev/null
+++ b/workspaces/libnpmversion/lib/retrieve-tag.js
@@ -0,0 +1,13 @@
+const { spawn } = require('@npmcli/git')
+const semver = require('semver')
+
+module.exports = async opts => {
+ const tag = (await spawn(
+ ['describe', '--tags', '--abbrev=0', '--match=*.*.*'],
+ opts)).stdout.trim()
+ const ver = semver.coerce(tag, { loose: true })
+ if (ver) {
+ return ver.version
+ }
+ throw new Error(`Tag is not a valid version: ${JSON.stringify(tag)}`)
+}
diff --git a/workspaces/libnpmversion/lib/tag.js b/workspaces/libnpmversion/lib/tag.js
new file mode 100644
index 000000000..095456b20
--- /dev/null
+++ b/workspaces/libnpmversion/lib/tag.js
@@ -0,0 +1,30 @@
+const git = require('@npmcli/git')
+
+module.exports = async (version, opts) => {
+ const {
+ signGitTag,
+ allowSameVersion,
+ tagVersionPrefix,
+ message,
+ } = opts
+
+ const tag = `${tagVersionPrefix}${version}`
+ const flags = ['-']
+
+ if (signGitTag) {
+ flags.push('s')
+ }
+
+ if (allowSameVersion) {
+ flags.push('f')
+ }
+
+ flags.push('m')
+
+ return git.spawn([
+ 'tag',
+ flags.join(''),
+ message.replace(/%s/g, version),
+ tag,
+ ], opts)
+}
diff --git a/workspaces/libnpmversion/lib/version.js b/workspaces/libnpmversion/lib/version.js
new file mode 100644
index 000000000..116a37555
--- /dev/null
+++ b/workspaces/libnpmversion/lib/version.js
@@ -0,0 +1,137 @@
+// called with all the options already set to their defaults
+
+const retrieveTag = require('./retrieve-tag.js')
+const semver = require('semver')
+const enforceClean = require('./enforce-clean.js')
+const writeJson = require('./write-json.js')
+const readJson = require('./read-json.js')
+const git = require('@npmcli/git')
+const commit = require('./commit.js')
+const tag = require('./tag.js')
+
+const runScript = require('@npmcli/run-script')
+
+module.exports = async (newversion, opts) => {
+ const {
+ path,
+ allowSameVersion,
+ gitTagVersion,
+ ignoreScripts,
+ preid,
+ pkg,
+ log,
+ } = opts
+
+ const { valid, clean, inc } = semver
+ const current = pkg.version || '0.0.0'
+ const currentClean = clean(current)
+
+ let newV
+ if (valid(newversion, { loose: true })) {
+ newV = clean(newversion, { loose: true })
+ } else if (newversion === 'from-git') {
+ newV = await retrieveTag(opts)
+ } else {
+ newV = inc(currentClean, newversion, { loose: true }, preid)
+ }
+
+ if (!newV) {
+ throw Object.assign(new Error('Invalid version: ' + newversion), {
+ current,
+ requested: newversion,
+ })
+ }
+
+ if (newV === currentClean && !allowSameVersion) {
+ throw Object.assign(new Error('Version not changed'), {
+ current,
+ requested: newversion,
+ newVersion: newV,
+ })
+ }
+
+ const isGitDir = newversion === 'from-git' || await git.is(opts)
+
+ // ok! now we know the new version, and the old version is in pkg
+
+ // - check if git dir is clean
+ // returns false if we should not keep doing git stuff
+ const doGit = gitTagVersion && isGitDir && await enforceClean(opts)
+
+ if (!ignoreScripts) {
+ await runScript({
+ ...opts,
+ pkg,
+ stdio: 'inherit',
+ event: 'preversion',
+ banner: log.level !== 'silent',
+ env: {
+ npm_old_version: current,
+ npm_new_version: newV,
+ },
+ })
+ }
+
+ // - update the files
+ pkg.version = newV
+ delete pkg._id
+ await writeJson(`${path}/package.json`, pkg)
+
+ // try to update shrinkwrap, but ok if this fails
+ const locks = [`${path}/package-lock.json`, `${path}/npm-shrinkwrap.json`]
+ const haveLocks = []
+ for (const lock of locks) {
+ try {
+ const sw = await readJson(lock)
+ sw.version = newV
+ if (sw.packages && sw.packages['']) {
+ sw.packages[''].version = newV
+ }
+ await writeJson(lock, sw)
+ haveLocks.push(lock)
+ } catch (er) {}
+ }
+
+ if (!ignoreScripts) {
+ await runScript({
+ ...opts,
+ pkg,
+ stdio: 'inherit',
+ event: 'version',
+ banner: log.level !== 'silent',
+ env: {
+ npm_old_version: current,
+ npm_new_version: newV,
+ },
+ })
+ }
+
+ if (doGit) {
+ // - git add, git commit, git tag
+ await git.spawn(['add', `${path}/package.json`], opts)
+ // sometimes people .gitignore their lockfiles
+ for (const lock of haveLocks) {
+ await git.spawn(['add', lock], opts).catch(() => {})
+ }
+ await commit(newV, opts)
+ await tag(newV, opts)
+ } else {
+ log.verbose('version', 'Not tagging: not in a git repo or no git cmd')
+ }
+
+ if (!ignoreScripts) {
+ await runScript({
+ ...opts,
+ pkg,
+ stdio: 'inherit',
+ event: 'postversion',
+ banner: log.level !== 'silent',
+ env: {
+ npm_old_version: current,
+ npm_new_version: newV,
+ },
+ })
+ }
+
+ return newV
+}
diff --git a/workspaces/libnpmversion/lib/write-json.js b/workspaces/libnpmversion/lib/write-json.js
new file mode 100644
index 000000000..f066d72c6
--- /dev/null
+++ b/workspaces/libnpmversion/lib/write-json.js
@@ -0,0 +1,16 @@
+// write the json back, preserving the line breaks and indent
+const { promisify } = require('util')
+const writeFile = promisify(require('fs').writeFile)
+const kIndent = Symbol.for('indent')
+const kNewline = Symbol.for('newline')
+
+module.exports = async (path, pkg) => {
+ const {
+ [kIndent]: indent = 2,
+ [kNewline]: newline = '\n',
+ } = pkg
+ delete pkg._id
+ const raw = JSON.stringify(pkg, null, indent) + '\n'
+ const data = newline === '\n' ? raw : raw.split('\n').join(newline)
+ return writeFile(path, data)
+}
diff --git a/workspaces/libnpmversion/map.js b/workspaces/libnpmversion/map.js
new file mode 100644
index 000000000..a08c78762
--- /dev/null
+++ b/workspaces/libnpmversion/map.js
@@ -0,0 +1 @@
+module.exports = test => test.replace(/^test/, 'lib')
diff --git a/workspaces/libnpmversion/package.json b/workspaces/libnpmversion/package.json
new file mode 100644
index 000000000..54a966799
--- /dev/null
+++ b/workspaces/libnpmversion/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "libnpmversion",
+ "version": "2.0.2",
+ "main": "lib/index.js",
+ "files": [
+ "bin",
+ "lib"
+ ],
+ "description": "library to do the things that 'npm version' does",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/npm/libnpmversion"
+ },
+ "author": "GitHub Inc.",
+ "license": "ISC",
+ "scripts": {
+ "lint": "eslint '**/*.js'",
+ "test": "tap",
+ "posttest": "npm run lint",
+ "snap": "tap",
+ "preversion": "npm test",
+ "postversion": "npm publish",
+ "prepublishOnly": "git push origin --follow-tags",
+ "postlint": "npm-template-check",
+ "lintfix": "npm run lint -- --fix"
+ },
+ "tap": {
+ "coverage-map": "map.js",
+ "check-coverage": true
+ },
+ "devDependencies": {
+ "require-inject": "^1.4.4",
+ "tap": "^15"
+ },
+ "dependencies": {
+ "@npmcli/git": "^2.0.7",
+ "@npmcli/run-script": "^2.0.0",
+ "json-parse-even-better-errors": "^2.3.1",
+ "semver": "^7.3.5",
+ "stringify-package": "^1.0.1"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16"
+ },
+ "templateOSS": {
+ "version": "2.4.1"
+ }
+}
diff --git a/workspaces/libnpmversion/tap-snapshots/test/commit.js.test.cjs b/workspaces/libnpmversion/tap-snapshots/test/commit.js.test.cjs
new file mode 100644
index 000000000..66bd61a93
--- /dev/null
+++ b/workspaces/libnpmversion/tap-snapshots/test/commit.js.test.cjs
@@ -0,0 +1,23 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/commit.js TAP generate args from options > default options 1`] = `
+Array [
+ "-m",
+ "v1.2.3",
+]
+`
+
+exports[`test/commit.js TAP generate args from options > non-default options 1`] = `
+Array [
+ "-n",
+ "--allow-empty",
+ "-S",
+ "-m",
+ "hello, 1.2.3, this is a message for you about 1.2.3.",
+]
+`
diff --git a/workspaces/libnpmversion/tap-snapshots/test/index.js.test.cjs b/workspaces/libnpmversion/tap-snapshots/test/index.js.test.cjs
new file mode 100644
index 000000000..6b79d41eb
--- /dev/null
+++ b/workspaces/libnpmversion/tap-snapshots/test/index.js.test.cjs
@@ -0,0 +1,66 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/index.js TAP all the defaults > must match snapshot 1`] = `
+Array [
+ "from-git",
+ Object {
+ "allowSameVersion": false,
+ "commitHooks": true,
+ "cwd": "{CWD}",
+ "force": false,
+ "gitTagVersion": true,
+ "ignoreScripts": false,
+ "log": Object {
+ "error": Function (...args),
+ "http": Function (...args),
+ "info": Function (...args),
+ "notice": Function (...args),
+ "pause": Function (...args),
+ "resume": Function (...args),
+ "silly": Function (...args),
+ "verbose": Function (...args),
+ "warn": Function (...args),
+ },
+ "message": "v%s",
+ "path": "{CWD}",
+ "pkg": Object {
+ "name": "package from rj",
+ },
+ "preid": null,
+ "scriptShell": undefined,
+ "signGitCommit": false,
+ "signGitTag": false,
+ "tagVersionPrefix": "v",
+ },
+]
+`
+
+exports[`test/index.js TAP set the package ahead of time > must match snapshot 1`] = `
+Array [
+ "major",
+ Object {
+ "allowSameVersion": true,
+ "commitHooks": false,
+ "cwd": "/some/path",
+ "force": true,
+ "gitTagVersion": false,
+ "ignoreScripts": true,
+ "log": Object {},
+ "message": "hello, i have a message for you",
+ "path": "/some/path",
+ "pkg": Object {
+ "name": "package set in options",
+ },
+ "preid": "rc",
+ "scriptShell": "/bin/bash",
+ "signGitCommit": true,
+ "signGitTag": true,
+ "tagVersionPrefix": "=",
+ },
+]
+`
diff --git a/workspaces/libnpmversion/tap-snapshots/test/read-json.js.test.cjs b/workspaces/libnpmversion/tap-snapshots/test/read-json.js.test.cjs
new file mode 100644
index 000000000..78f4473e0
--- /dev/null
+++ b/workspaces/libnpmversion/tap-snapshots/test/read-json.js.test.cjs
@@ -0,0 +1,28 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/read-json.js TAP do not strip or mutate anything > crlf-tabs.json 1`] = `
+Object {
+ "name": "curly leaflets tabula rasa",
+ "version": "9",
+}
+`
+
+exports[`test/read-json.js TAP do not strip or mutate anything > package.json 1`] = `
+Object {
+ "_someField": "someValue",
+ "bin": "../../../../../../etc/passwd",
+ "name": "foo",
+}
+`
+
+exports[`test/read-json.js TAP do not strip or mutate anything > space-tabs.json 1`] = `
+Object {
+ "name": "spacetabular",
+ "version": "9000.0.1",
+}
+`
diff --git a/workspaces/libnpmversion/tap-snapshots/test/tag.js.test.cjs b/workspaces/libnpmversion/tap-snapshots/test/tag.js.test.cjs
new file mode 100644
index 000000000..e35b968a7
--- /dev/null
+++ b/workspaces/libnpmversion/tap-snapshots/test/tag.js.test.cjs
@@ -0,0 +1,22 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/tag.js TAP generate args from options > default options 1`] = `
+Array [
+ "-m",
+ "v1.2.3",
+ "undefined1.2.3",
+]
+`
+
+exports[`test/tag.js TAP generate args from options > non-default options 1`] = `
+Array [
+ "-sfm",
+ "hello, 1.2.3, this is a message for you about 1.2.3.",
+ "undefined1.2.3",
+]
+`
diff --git a/workspaces/libnpmversion/test/commit.js b/workspaces/libnpmversion/test/commit.js
new file mode 100644
index 000000000..6d10e1103
--- /dev/null
+++ b/workspaces/libnpmversion/test/commit.js
@@ -0,0 +1,17 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+const commit = requireInject('../lib/commit.js', {
+ '@npmcli/git': { spawn: args => args.slice(1) },
+})
+
+t.test('generate args from options', async t => {
+ t.matchSnapshot(await commit('1.2.3', {
+ message: 'v%s',
+ }), 'default options')
+ t.matchSnapshot(await commit('1.2.3', {
+ commitHooks: false,
+ allowSameVersion: true,
+ signGitCommit: true,
+ message: 'hello, %s, this is a message for you about %s.',
+ }), 'non-default options')
+})
diff --git a/workspaces/libnpmversion/test/enforce-clean.js b/workspaces/libnpmversion/test/enforce-clean.js
new file mode 100644
index 000000000..9a489d6f5
--- /dev/null
+++ b/workspaces/libnpmversion/test/enforce-clean.js
@@ -0,0 +1,68 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+const enforceClean = requireInject('../lib/enforce-clean.js', {
+ '@npmcli/git': {
+ isClean: async ({ cwd }) => {
+ switch (cwd) {
+ case 'clean': return true
+ case 'unclean': return false
+ case 'nogit': throw Object.assign(new Error('no git'), {
+ code: 'ENOGIT',
+ })
+ case 'error': throw new Error('poop')
+ default:
+ console.error('unknown cwd: %j', cwd)
+ process.exit(1)
+ }
+ },
+ },
+})
+
+const warnings = []
+const log = { warn: (...msg) => warnings.push(msg) }
+
+t.test('clean, ok', t =>
+ t.resolveMatch(enforceClean({ log, cwd: 'clean' }), true)
+ .then(() => t.strictSame(warnings, []))
+ .then(() => {
+ warnings.length = 0
+ }))
+
+t.test('unclean, no force, throws', t =>
+ t.rejects(enforceClean({ log, cwd: 'unclean' }))
+ .then(() => t.strictSame(warnings, []))
+ .then(() => {
+ warnings.length = 0
+ }))
+
+t.test('unclean, forced, no throw', t =>
+ t.resolveMatch(enforceClean({ log, cwd: 'unclean', force: true }), true)
+ .then(() => t.strictSame(warnings, [
+ [
+ 'version',
+ 'Git working directory not clean, proceeding forcefully.',
+ ],
+ ]))
+ .then(() => {
+ warnings.length = 0
+ }))
+
+t.test('nogit, return false, no throw', t =>
+ t.resolveMatch(enforceClean({ log, cwd: 'nogit' }), false)
+ .then(() => t.strictSame(warnings, [
+ [
+ 'version',
+ 'This is a Git checkout, but the git command was not found.',
+ 'npm could not create a Git tag for this release!',
+ ],
+ ]))
+ .then(() => {
+ warnings.length = 0
+ }))
+
+t.test('other error, throw it', t =>
+ t.rejects(enforceClean({ log, cwd: 'error' }), new Error('poop'))
+ .then(() => t.strictSame(warnings, []))
+ .then(() => {
+ warnings.length = 0
+ }))
diff --git a/workspaces/libnpmversion/test/index.js b/workspaces/libnpmversion/test/index.js
new file mode 100644
index 000000000..8c853c679
--- /dev/null
+++ b/workspaces/libnpmversion/test/index.js
@@ -0,0 +1,39 @@
+// just verify it sets up the default options correctly
+const t = require('tap')
+const requireInject = require('require-inject')
+const kIndent = Symbol.for('indent')
+const kNewline = Symbol.for('newline')
+const index = requireInject('../lib/index.js', {
+ '../lib/version.js': (newversion, opts) => [newversion, opts],
+ '../lib/read-json.js': () => ({
+ name: 'package from rj',
+ [kIndent]: ' ',
+ [kNewline]: '\n',
+ }),
+})
+
+t.cleanSnapshot = s => s.split(process.cwd()).join('{CWD}')
+ .split(process.cwd().replace(/\\/g, '\\\\')).join('{CWD}')
+
+t.test('all the defaults', async t =>
+ t.matchSnapshot(await index('from-git')))
+
+t.test('set the package ahead of time', async t =>
+ t.matchSnapshot(await index('major', {
+ pkg: { name: 'package set in options' },
+ path: '/some/path',
+ cwd: 'different cwd, this should not show up',
+ allowSameVersion: true,
+ tagVersionPrefix: '=',
+ commitHooks: false,
+ gitTagVersion: false,
+ signGitCommit: true,
+ signGitTag: true,
+ force: true,
+ ignoreScripts: true,
+ scriptShell: '/bin/bash',
+ preid: 'rc',
+ log: {},
+ message: 'hello, i have a message for you',
+ someOtherRandomField: 'this should not show up',
+ })))
diff --git a/workspaces/libnpmversion/test/proc-log.js b/workspaces/libnpmversion/test/proc-log.js
new file mode 100644
index 000000000..54f7d0b57
--- /dev/null
+++ b/workspaces/libnpmversion/test/proc-log.js
@@ -0,0 +1,11 @@
+const procLog = require('../lib/proc-log.js')
+const t = require('tap')
+process.once('log', (...args) => t.same(args, ['warn', 1, 2, 3]))
+procLog.warn(1, 2, 3)
+t.same(Object.keys(procLog), [
+ 'notice', 'error',
+ 'warn', 'info',
+ 'verbose', 'http',
+ 'silly', 'pause',
+ 'resume',
+])
diff --git a/workspaces/libnpmversion/test/read-json.js b/workspaces/libnpmversion/test/read-json.js
new file mode 100644
index 000000000..4ead591b8
--- /dev/null
+++ b/workspaces/libnpmversion/test/read-json.js
@@ -0,0 +1,37 @@
+const t = require('tap')
+const readJson = require('../lib/read-json.js')
+
+const kIndent = Symbol.for('indent')
+const kNewline = Symbol.for('newline')
+
+t.test('do not strip or mutate anything', async t => {
+ const path = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ _someField: 'someValue',
+ bin: '../../../../../../etc/passwd',
+ }, null, 2),
+ 'crlf-tabs.json': JSON.stringify({
+ name: 'curly leaflets tabula rasa',
+ version: '9',
+ }, null, '\t').replace(/\n/g, '\r\n'),
+ 'space-tabs.json': JSON.stringify({
+ name: 'spacetabular',
+ version: '9000.0.1',
+ }, null, ' \t \t'),
+ })
+ const basic = await readJson(path + '/package.json')
+ t.matchSnapshot(basic, 'package.json')
+ t.equal(basic[kIndent], ' ')
+ t.equal(basic[kNewline], '\n')
+
+ const crlfTabs = await readJson(path + '/crlf-tabs.json')
+ t.matchSnapshot(crlfTabs, 'crlf-tabs.json')
+ t.equal(crlfTabs[kIndent], '\t')
+ t.equal(crlfTabs[kNewline], '\r\n')
+
+ const spaceTabs = await readJson(path + '/space-tabs.json')
+ t.matchSnapshot(spaceTabs, 'space-tabs.json')
+ t.equal(spaceTabs[kIndent], ' \t \t')
+ t.equal(spaceTabs[kNewline], '\n')
+})
diff --git a/workspaces/libnpmversion/test/retrieve-tag.js b/workspaces/libnpmversion/test/retrieve-tag.js
new file mode 100644
index 000000000..29155acdf
--- /dev/null
+++ b/workspaces/libnpmversion/test/retrieve-tag.js
@@ -0,0 +1,20 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+let tag
+const retrieveTag = requireInject('../lib/retrieve-tag.js', {
+ '@npmcli/git': {
+ spawn: async (cmd, opts) => ({ stdout: tag + '\n' }),
+ },
+})
+
+t.test('not a valid semver tag', t => {
+ tag = 'this is not a version'
+ return t.rejects(retrieveTag(), {
+ message: 'Tag is not a valid version: "this is not a version"',
+ })
+})
+
+t.test('yes a valid semver tag', async t => {
+ tag = 'this is a version tho: Release-1.2.3 candidate'
+ t.equal(await retrieveTag(), '1.2.3')
+})
diff --git a/workspaces/libnpmversion/test/tag.js b/workspaces/libnpmversion/test/tag.js
new file mode 100644
index 000000000..7365f2139
--- /dev/null
+++ b/workspaces/libnpmversion/test/tag.js
@@ -0,0 +1,16 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+const tag = requireInject('../lib/tag.js', {
+ '@npmcli/git': { spawn: args => args.slice(1) },
+})
+
+t.test('generate args from options', async t => {
+ t.matchSnapshot(await tag('1.2.3', {
+ message: 'v%s',
+ }), 'default options')
+ t.matchSnapshot(await tag('1.2.3', {
+ signGitTag: true,
+ allowSameVersion: true,
+ message: 'hello, %s, this is a message for you about %s.',
+ }), 'non-default options')
+})
diff --git a/workspaces/libnpmversion/test/version.js b/workspaces/libnpmversion/test/version.js
new file mode 100644
index 000000000..dfaa95de3
--- /dev/null
+++ b/workspaces/libnpmversion/test/version.js
@@ -0,0 +1,368 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+
+const actionLog = []
+
+const log = {
+ verbose: (...msg) => actionLog.push(['verbose', ...msg]),
+}
+
+const gitMock = {
+ is: async opts => !/\bnot-git$/.test(opts.path),
+ spawn: async (args, opts) => actionLog.push(['spawn', args, opts]),
+}
+
+const version = requireInject('../lib/version.js', {
+ '../lib/enforce-clean.js': async () => true,
+ '../lib/write-json.js': async (file, data) => actionLog.push(['write-json', file, data]),
+ '../lib/commit.js': async (version, opts) => actionLog.push(['commit', version, opts]),
+ '../lib/tag.js': async (version, opts) => actionLog.push(['tag', version, opts]),
+ '../lib/retrieve-tag.js': async (opts) => {
+ if (/\bnot-git$/.test(opts.path)) {
+ throw new Error('not a git dir')
+ }
+ actionLog.push(['retrieve-tag', opts])
+ return '1.2.3'
+ },
+ '@npmcli/git': gitMock,
+ '@npmcli/run-script': async opt => actionLog.push(['run-script', opt.event, opt.env, opt]),
+})
+
+t.test('test out bumping the version in all the ways', async t => {
+ const pkg = {
+ name: 'foo',
+ version: '1.2.0',
+ }
+ const lock = {
+ name: 'foo',
+ version: '1.2.0',
+ dependencies: {},
+ }
+
+ const dir = t.testdir({
+ git: {
+ 'package-lock.json': JSON.stringify(lock, null, 2),
+ },
+ 'not-git': {
+ 'npm-shrinkwrap.json': JSON.stringify({
+ ...lock,
+ packages: {
+ '': { ...pkg },
+ },
+ }, null, 2),
+ },
+ })
+
+ await t.test('git dir', async t => {
+ t.afterEach(async () => {
+ actionLog.length = 0
+ })
+ const path = `${dir}/git`
+ await t.test('major', async t => {
+ // for this one, let's pretend that the package-lock.json is .gitignored
+ const { spawn } = gitMock
+ t.teardown(() => {
+ gitMock.spawn = spawn
+ })
+ gitMock.spawn = async (args, opts) => {
+ if (args[0] !== 'add' || !args.some(a => /package-lock\.json$/.test(a))) {
+ return spawn(args, opts)
+ }
+ throw new Error('no addy the locky fiel please & thanky i ignoring it')
+ }
+ t.equal(await version('major', { path, log, pkg, gitTagVersion: true }), '2.0.0')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '1.2.0', npm_new_version: '2.0.0' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '1.2.0', npm_new_version: '2.0.0' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['commit', '2.0.0', { path, pkg }],
+ ['tag', '2.0.0', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '1.2.0', npm_new_version: '2.0.0' }],
+ ])
+ t.equal(pkg.version, '2.0.0')
+ })
+ await t.test('minor (ignore scripts)', async t => {
+ t.equal(await version('minor',
+ { path, log, pkg, ignoreScripts: true, gitTagVersion: true }), '2.1.0')
+ t.match(actionLog, [
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '2.1.0', { path, pkg }],
+ ['tag', '2.1.0', { path, pkg }],
+ ])
+ t.equal(pkg.version, '2.1.0')
+ })
+ await t.test('patch', async t => {
+ t.equal(await version('patch', { path, log, pkg, gitTagVersion: true }), '2.1.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '2.1.0', npm_new_version: '2.1.1' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.0', npm_new_version: '2.1.1' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '2.1.1', { path, pkg }],
+ ['tag', '2.1.1', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '2.1.0', npm_new_version: '2.1.1' }],
+ ])
+ t.equal(pkg.version, '2.1.1')
+ })
+ await t.test('pre', async t => {
+ t.equal(await version('pre', { path, log, pkg, gitTagVersion: true }), '2.1.1-0')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '2.1.1', npm_new_version: '2.1.1-0' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.1', npm_new_version: '2.1.1-0' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '2.1.1-0', { path, pkg }],
+ ['tag', '2.1.1-0', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '2.1.1', npm_new_version: '2.1.1-0' }],
+ ])
+ t.equal(pkg.version, '2.1.1-0')
+ })
+ await t.test('pre with preid', async t => {
+ t.equal(await version('pre', { path, log, preid: 'alpha', pkg, gitTagVersion: true }),
+ '2.1.1-alpha.0')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '2.1.1-0',
+ npm_new_version: '2.1.1-alpha.0' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.1-0', npm_new_version: '2.1.1-alpha.0' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '2.1.1-alpha.0', { path, pkg }],
+ ['tag', '2.1.1-alpha.0', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '2.1.1-0',
+ npm_new_version: '2.1.1-alpha.0' }],
+ ])
+ t.equal(pkg.version, '2.1.1-alpha.0')
+ })
+ await t.test('skips git tag when gitTagVersion is false', async t => {
+ t.equal(await version('minor', { path, log, pkg, ignoreScripts: true, gitTagVersion: false }),
+ '2.2.0')
+ t.match(actionLog, [
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ])
+ t.equal(pkg.version, '2.2.0')
+ })
+ await t.test('explicit version', async t => {
+ t.equal(await version('=v3.2.1', { path, log, pkg, gitTagVersion: true }), '3.2.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '2.2.0', npm_new_version: '3.2.1' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.2.0', npm_new_version: '3.2.1' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '3.2.1', { path, pkg }],
+ ['tag', '3.2.1', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '2.2.0', npm_new_version: '3.2.1' }],
+ ])
+ t.equal(pkg.version, '3.2.1')
+ })
+ await t.test('invalid version', async t => {
+ await t.rejects(version('invalid version', { path, log, pkg }), {
+ message: 'Invalid version: invalid version',
+ current: '3.2.1',
+ requested: 'invalid version',
+ })
+ })
+ await t.test('same version, not allowed', async t => {
+ await t.rejects(version('=v3.2.1', { path, log, pkg }), {
+ message: 'Version not changed',
+ current: '3.2.1',
+ requested: '=v3.2.1',
+ newVersion: '3.2.1',
+ })
+ })
+ await t.test('same version, is allowed', async t => {
+ t.equal(await version('=v3.2.1',
+ { path, log, pkg, allowSameVersion: true, gitTagVersion: true }), '3.2.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg, allowSameVersion: true }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg, allowSameVersion: true }],
+ ['commit', '3.2.1', { path, pkg, allowSameVersion: true }],
+ ['tag', '3.2.1', { path, pkg, allowSameVersion: true }],
+ ['run-script', 'postversion', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' }],
+ ])
+ t.equal(pkg.version, '3.2.1')
+ })
+ await t.test('from git', async t => {
+ t.equal(await version('from-git', { path, log, pkg, gitTagVersion: true }), '1.2.3')
+ t.match(actionLog, [
+ ['retrieve-tag', { path, pkg }],
+ ['run-script', 'preversion', { npm_old_version: '3.2.1', npm_new_version: '1.2.3' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '3.2.1', npm_new_version: '1.2.3' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '1.2.3', { path, pkg }],
+ ['tag', '1.2.3', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '3.2.1', npm_new_version: '1.2.3' }],
+ ])
+ t.equal(pkg.version, '1.2.3')
+ })
+ await t.test('no current version', async t => {
+ delete pkg.version
+ t.equal(await version('2.3.4', { path, log, pkg, gitTagVersion: true }), '2.3.4')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '0.0.0', npm_new_version: '2.3.4' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/package-lock.json', pkg],
+ ['run-script', 'version', { npm_old_version: '0.0.0', npm_new_version: '2.3.4' }],
+ ['spawn', ['add', path + '/package.json'], { path, pkg }],
+ ['spawn', ['add', path + '/package-lock.json'], { path, pkg }],
+ ['commit', '2.3.4', { path, pkg }],
+ ['tag', '2.3.4', { path, pkg }],
+ ['run-script', 'postversion', { npm_old_version: '0.0.0', npm_new_version: '2.3.4' }],
+ ])
+ t.equal(pkg.version, '2.3.4')
+ })
+ })
+
+ await t.test('not a git dir', async t => {
+ pkg.version = '1.2.0'
+ t.afterEach(async () => {
+ actionLog.length = 0
+ })
+ const path = `${dir}/not-git`
+ await t.test('major', async t => {
+ t.equal(await version('major', { path, log, pkg }), '2.0.0')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '1.2.0', npm_new_version: '2.0.0' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '1.2.0', npm_new_version: '2.0.0' }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion', { npm_old_version: '1.2.0', npm_new_version: '2.0.0' }],
+ ])
+ t.equal(pkg.version, '2.0.0')
+ })
+ await t.test('minor (ignore scripts)', async t => {
+ t.equal(await version('minor', { path, log, pkg, ignoreScripts: true }), '2.1.0')
+ t.match(actionLog, [
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ])
+ t.equal(pkg.version, '2.1.0')
+ })
+ await t.test('patch', async t => {
+ t.equal(await version('patch', { path, log, pkg }), '2.1.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '2.1.0', npm_new_version: '2.1.1' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.0', npm_new_version: '2.1.1' }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion', { npm_old_version: '2.1.0', npm_new_version: '2.1.1' }],
+ ])
+ t.equal(pkg.version, '2.1.1')
+ })
+ await t.test('pre', async t => {
+ t.equal(await version('pre', { path, log, pkg }), '2.1.1-0')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '2.1.1', npm_new_version: '2.1.1-0' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.1', npm_new_version: '2.1.1-0' }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion', { npm_old_version: '2.1.1', npm_new_version: '2.1.1-0' }],
+ ])
+ t.equal(pkg.version, '2.1.1-0')
+ })
+ await t.test('pre with preid', async t => {
+ t.equal(await version('pre', { path, log, preid: 'alpha', pkg }), '2.1.1-alpha.0')
+ t.match(actionLog, [
+ ['run-script', 'preversion',
+ { npm_old_version: '2.1.1-0', npm_new_version: '2.1.1-alpha.0' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.1-0', npm_new_version: '2.1.1-alpha.0' }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion',
+ { npm_old_version: '2.1.1-0', npm_new_version: '2.1.1-alpha.0' }],
+ ])
+ t.equal(pkg.version, '2.1.1-alpha.0')
+ })
+ await t.test('explicit version', async t => {
+ t.equal(await version('=v3.2.1', { path, log, pkg }), '3.2.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion',
+ { npm_old_version: '2.1.1-alpha.0', npm_new_version: '3.2.1' }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '2.1.1-alpha.0', npm_new_version: '3.2.1' }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion',
+ { npm_old_version: '2.1.1-alpha.0', npm_new_version: '3.2.1' }],
+ ])
+ t.equal(pkg.version, '3.2.1')
+ })
+ await t.test('invalid version', async t => {
+ await t.rejects(version('invalid version', { path, log, pkg }), {
+ message: 'Invalid version: invalid version',
+ current: '3.2.1',
+ requested: 'invalid version',
+ })
+ })
+ await t.test('same version, not allowed', async t => {
+ await t.rejects(version('=v3.2.1', { path, log, pkg }), {
+ message: 'Version not changed',
+ current: '3.2.1',
+ requested: '=v3.2.1',
+ newVersion: '3.2.1',
+ })
+ })
+ await t.test('same version, is allowed', async t => {
+ t.equal(await version('=v3.2.1', { path, log, pkg, allowSameVersion: true }), '3.2.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' },
+ { banner: true }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' },
+ { banner: true }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' },
+ { banner: true }],
+ ])
+ t.equal(pkg.version, '3.2.1')
+ })
+ await t.test('same version, is allowed (silent mode)', async t => {
+ t.equal(await version('=v3.2.1',
+ { path, log: { ...log, level: 'silent' }, pkg, allowSameVersion: true }), '3.2.1')
+ t.match(actionLog, [
+ ['run-script', 'preversion', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' },
+ { banner: false }],
+ ['write-json', path + '/package.json', pkg],
+ ['write-json', path + '/npm-shrinkwrap.json', pkg],
+ ['run-script', 'version', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' },
+ { banner: false }],
+ ['verbose', 'version', 'Not tagging: not in a git repo or no git cmd'],
+ ['run-script', 'postversion', { npm_old_version: '3.2.1', npm_new_version: '3.2.1' },
+ { banner: false }],
+ ])
+ t.equal(pkg.version, '3.2.1')
+ })
+ await t.test('from git', async t => {
+ await t.rejects(version('from-git', { path, log, pkg }), {
+ message: 'not a git dir',
+ })
+ })
+ })
+})
diff --git a/workspaces/libnpmversion/test/write-json.js b/workspaces/libnpmversion/test/write-json.js
new file mode 100644
index 000000000..a8e5b1572
--- /dev/null
+++ b/workspaces/libnpmversion/test/write-json.js
@@ -0,0 +1,60 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+const fs = require('fs')
+const writeJson = requireInject('../lib/write-json.js', {
+ fs: {
+ ...fs,
+ writeFile: (path, data, cb) => cb(null, [path, data]),
+ },
+})
+
+const kIndent = Symbol.for('indent')
+const kNewline = Symbol.for('newline')
+
+t.test('write json with newlines and indent set', async t => {
+ t.same(await writeJson('x', {
+ [kNewline]: '\r\n',
+ [kIndent]: 3,
+ a: 1,
+ b: [2, 3],
+ }), [
+ 'x',
+ '{\r\n' +
+ ' "a": 1,\r\n' +
+ ' "b": [\r\n' +
+ ' 2,\r\n' +
+ ' 3\r\n' +
+ ' ]\r\n' +
+ '}\r\n',
+ ], 'numeric three space indent, CRLF line breaks')
+
+ t.same(await writeJson('x', {
+ [kNewline]: 'XYZ\n',
+ [kIndent]: '\t',
+ a: 1,
+ b: [2, 3],
+ }), [
+ 'x',
+ '{XYZ\n' +
+ '\t"a": 1,XYZ\n' +
+ '\t"b": [XYZ\n' +
+ '\t\t2,XYZ\n' +
+ '\t\t3XYZ\n' +
+ '\t]XYZ\n' +
+ '}XYZ\n',
+ ], 'string tap indent, CRLF line breaks')
+
+ t.same(await writeJson('x', {
+ a: 1,
+ b: [2, 3],
+ }), [
+ 'x',
+ '{\n' +
+ ' "a": 1,\n' +
+ ' "b": [\n' +
+ ' 2,\n' +
+ ' 3\n' +
+ ' ]\n' +
+ '}\n',
+ ], 'default newline and indent')
+})