Skip to content

Commit

Permalink
feat(view): output all workspaces even when one 404s
Browse files Browse the repository at this point in the history
Fixes #5444
  • Loading branch information
lukekarrys committed May 13, 2024
1 parent 3c022b8 commit 76fd359
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 3 deletions.
20 changes: 18 additions & 2 deletions lib/commands/view.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const columns = require('cli-columns')
const { readFile } = require('fs/promises')
const jsonParse = require('json-parse-even-better-errors')
const { log, output } = require('proc-log')
const { log, output, META } = require('proc-log')
const npa = require('npm-package-arg')
const { resolve } = require('path')
const formatBytes = require('../utils/format-bytes.js')
Expand All @@ -11,6 +11,8 @@ const { inspect } = require('util')
const { packument } = require('pacote')
const Queryable = require('../utils/queryable.js')
const BaseCommand = require('../base-cmd.js')
const { getError } = require('../utils/error-message.js')
const { jsonError, outputError } = require('../utils/output-error.js')

const readJson = async file => jsonParse(await readFile(file, 'utf8'))

Expand Down Expand Up @@ -103,10 +105,24 @@ class View extends BaseCommand {
return this.exec([pkg, ...rest])
}

const json = this.npm.config.get('json')
await this.setWorkspaces()

for (const name of this.workspaceNames) {
await this.#viewPackage(`${name}${pkg.slice(1)}`, rest, { workspace: true })
try {
await this.#viewPackage(`${name}${pkg.slice(1)}`, rest, { workspace: true })
} catch (e) {
const err = getError(e, { npm: this.npm, command: this })
if (err.code !== 'E404') {
throw e
}
if (json) {
output.buffer({ [META]: true, jsonError: { [name]: jsonError(err, this.npm) } })
} else {
outputError(err)
}
process.exitCode = 1
}
}
}

Expand Down
134 changes: 134 additions & 0 deletions tap-snapshots/test/lib/commands/view.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,140 @@ [email protected] 'claudia'
[email protected] 'claudia'
`

exports[`test/lib/commands/view.js TAP workspaces 404 workspaces basic > must match snapshot 1`] = `
[[email protected] | ACME | deps: 2 | versions: 2
green is a very important color
DEPRECATED!! - true
keywords: colors, green, crayola
bin: green
dist
.tarball: http://hm.green.com/1.0.0.tgz
.shasum: 123
.integrity: ---
.unpackedSize: 1.0 GB
dependencies:
red: 1.0.0
yellow: 1.0.0
maintainers:
- claudia <[[email protected]>
- isaacs <[[email protected]>
dist-tags:
latest: 1.0.0
error code E404
error 404 404
`

exports[`test/lib/commands/view.js TAP workspaces 404 workspaces json > must match snapshot 1`] = `
{
"green": {
"_id": "green",
"name": "green",
"dist-tags": {
"latest": "1.0.0"
},
"maintainers": [
{
"name": "claudia",
"email": "[email protected]",
"twitter": "cyellow"
},
{
"name": "isaacs",
"email": "[email protected]",
"twitter": "iyellow"
}
],
"keywords": [
"colors",
"green",
"crayola"
],
"versions": [
"1.0.0",
"1.0.1"
],
"version": "1.0.0",
"description": "green is a very important color",
"bugs": {
"url": "http://bugs.green.com"
},
"deprecated": true,
"repository": {
"url": "http://repository.green.com"
},
"license": {
"type": "ACME"
},
"bin": {
"green": "bin/green.js"
},
"dependencies": {
"red": "1.0.0",
"yellow": "1.0.0"
},
"dist": {
"shasum": "123",
"tarball": "http://hm.green.com/1.0.0.tgz",
"integrity": "---",
"fileCount": 1,
"unpackedSize": 1000000000
}
},
"error": {
"missing-package": {
"code": "E404",
"summary": "404",
"detail": ""
}
}
}
`

exports[`test/lib/commands/view.js TAP workspaces 404 workspaces non-404 error rejects > must match snapshot 1`] = `
[[email protected] | ACME | deps: 2 | versions: 2
green is a very important color
DEPRECATED!! - true
keywords: colors, green, crayola
bin: green
dist
.tarball: http://hm.green.com/1.0.0.tgz
.shasum: 123
.integrity: ---
.unpackedSize: 1.0 GB
dependencies:
red: 1.0.0
yellow: 1.0.0
maintainers:
- claudia <[[email protected]>
- isaacs <[[email protected]>
dist-tags:
latest: 1.0.0
error Unknown error
`

exports[`test/lib/commands/view.js TAP workspaces 404 workspaces non-404 error rejects with single arg > must match snapshot 1`] = `
green:
1.0.0
unknown-error:
error Unknown error
`

exports[`test/lib/commands/view.js TAP workspaces all workspaces --json > must match snapshot 1`] = `
{
"green": {
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/mock-logs.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const logsByTitle = (logs) => ({
module.exports = () => {
const outputs = []
const outputErrors = []
const fullOutput = []

const levelLogs = []
const logs = Object.defineProperties([], {
Expand Down Expand Up @@ -53,6 +54,7 @@ module.exports = () => {
// in the future if/when we refactor what logs look like.
if (!isLog(str)) {
outputErrors.push(str)
fullOutput.push(str)
return
}

Expand All @@ -70,12 +72,14 @@ module.exports = () => {
const level = stripAnsi(rawLevel)

logs.push(str.replaceAll(prefix, `${level} `))
fullOutput.push(str.replaceAll(prefix, `${level} `))
levelLogs.push({ level, message: str.replaceAll(prefix, '') })
},
},
stdout: {
write: (str) => {
outputs.push(trimTrailingNewline(str))
fullOutput.push(trimTrailingNewline(str))
},
},
}
Expand All @@ -88,9 +92,12 @@ module.exports = () => {
clearOutput: () => {
outputs.length = 0
outputErrors.length = 0
fullOutput.length = 0
},
outputErrors,
joinedOutputError: () => joinAndTrimTrailingNewlines(outputs),
fullOutput,
joinedFullOutput: () => joinAndTrimTrailingNewlines(fullOutput),
logs,
clearLogs: () => {
levelLogs.length = 0
Expand Down
71 changes: 70 additions & 1 deletion test/lib/commands/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,24 @@ const packument = (nv, opts) => {
},
},
}

if (nv.type === 'git') {
return mocks[nv.hosted.project]
}

if (nv.raw === './blue') {
return mocks.blue
}
return mocks[nv.name]

if (mocks[nv.name]) {
return mocks[nv.name]
}

if (nv.name === 'unknown-error') {
throw new Error('Unknown error')
}

throw Object.assign(new Error('404'), { code: 'E404' })
}

const loadMockNpm = async function (t, opts = {}) {
Expand Down Expand Up @@ -543,6 +554,24 @@ t.test('workspaces', async t => {
},
}

const prefixDir404 = {
'test-workspace-b': {
'package.json': JSON.stringify({
name: 'missing-package',
version: '1.2.3',
}),
},
}

const prefixDirError = {
'test-workspace-b': {
'package.json': JSON.stringify({
name: 'unknown-error',
version: '1.2.3',
}),
},
}

t.test('all workspaces', async t => {
const { view, joinedOutput } = await loadMockNpm(t, {
prefixDir,
Expand Down Expand Up @@ -624,6 +653,46 @@ t.test('workspaces', async t => {
t.matchSnapshot(joinedOutput())
t.matchSnapshot(logs.warn, 'should have warning of ignoring workspaces')
})

t.test('404 workspaces', async t => {
t.test('basic', async t => {
const { view, joinedFullOutput } = await loadMockNpm(t, {
prefixDir: { ...prefixDir, ...prefixDir404 },
config: { workspaces: true, loglevel: 'error' },
})
await view.exec([])
t.matchSnapshot(joinedFullOutput())
t.equal(process.exitCode, 1)
})

t.test('json', async t => {
const { view, joinedFullOutput } = await loadMockNpm(t, {
prefixDir: { ...prefixDir, ...prefixDir404 },
config: { workspaces: true, json: true, loglevel: 'error' },
})
await view.exec([])
t.matchSnapshot(joinedFullOutput())
t.equal(process.exitCode, 1)
})

t.test('non-404 error rejects', async t => {
const { view, joinedFullOutput } = await loadMockNpm(t, {
prefixDir: { ...prefixDir, ...prefixDirError },
config: { workspaces: true, loglevel: 'error' },
})
await t.rejects(view.exec([]))
t.matchSnapshot(joinedFullOutput())
})

t.test('non-404 error rejects with single arg', async t => {
const { view, joinedFullOutput } = await loadMockNpm(t, {
prefixDir: { ...prefixDir, ...prefixDirError },
config: { workspaces: true, loglevel: 'error' },
})
await t.rejects(view.exec(['.', 'version']))
t.matchSnapshot(joinedFullOutput())
})
})
})

t.test('completion', async t => {
Expand Down

0 comments on commit 76fd359

Please sign in to comment.