Skip to content

Unit test config commands + fixes and refactors #2001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 27 additions & 18 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ const { defaults, types } = require('./utils/config.js')
const usageUtil = require('./utils/usage.js')
const output = require('./utils/output.js')

const editor = require('editor')
const mkdirp = require('mkdirp-infer-owner')
const { dirname } = require('path')
const { promisify } = require('util')
const fs = require('fs')
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const editor = promisify(require('editor'))
const { EOL } = require('os')
const ini = require('ini')

Expand All @@ -28,18 +28,25 @@ const cmd = (args, cb) => config(args).then(() => cb()).catch(cb)

const completion = (opts, cb) => {
const argv = opts.conf.argv.remain
if (argv[1] !== 'config') argv.unshift('config')
if (argv[1] !== 'config') {
argv.unshift('config')
}

if (argv.length === 2) {
const cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit']
if (opts.partialWord !== 'l') cmds.push('list')
if (opts.partialWord !== 'l') {
cmds.push('list')
}
return cb(null, cmds)
}

const action = argv[2]
switch (action) {
case 'set':
// todo: complete with valid values, if possible.
if (argv.length > 3) return cb(null, [])
if (argv.length > 3) {
return cb(null, [])
}
// fallthrough
/* eslint no-fallthrough:0 */
case 'get':
Expand All @@ -49,12 +56,14 @@ const completion = (opts, cb) => {
case 'edit':
case 'list':
case 'ls':
return cb(null, [])
default:
return cb(null, [])
}
}

const UsageError = () =>
Object.assign(new Error(usage), { code: 'EUSAGE' })

const config = async ([action, key, val]) => {
npm.log.disableProgress()
try {
Expand All @@ -72,13 +81,13 @@ const config = async ([action, key, val]) => {
break
case 'list':
case 'ls':
await (npm.config.get('json') ? listJson() : list())
await (npm.flatOptions.json ? listJson() : list())
break
case 'edit':
await edit()
break
default:
throw usage
throw UsageError()
}
} finally {
npm.log.enableProgress()
Expand All @@ -87,7 +96,7 @@ const config = async ([action, key, val]) => {

const set = async (key, val) => {
if (key === undefined) {
throw usage
throw UsageError()
}

if (val === undefined) {
Expand All @@ -103,9 +112,7 @@ const set = async (key, val) => {
key = key.trim()
val = val.trim()
npm.log.info('config', 'set %j %j', key, val)
const where = npm.config.get('global') ? 'global' : 'user'
const validBefore = npm.config.data.get(where).valid
console.error('validBefore?', validBefore)
const where = npm.flatOptions.global ? 'global' : 'user'
npm.config.set(key, val, where)
if (!npm.config.validate(where)) {
npm.log.warn('config', 'omitting invalid config values')
Expand All @@ -127,18 +134,18 @@ const get = async key => {

const del = async key => {
if (!key) {
throw usage
throw UsageError()
}

const where = npm.config.get('global') ? 'global' : 'user'
const where = npm.flatOptions.global ? 'global' : 'user'
npm.config.delete(key, where)
await npm.config.save(where)
}

const edit = async () => {
const { editor: e, global } = npm.flatOptions
if (!e) {
throw new Error('No `editor` config or EDITOR envionment variable set')
throw new Error('No `editor` config or EDITOR environment variable set')
}

const where = global ? 'global' : 'user'
Expand All @@ -147,10 +154,14 @@ const edit = async () => {
// save first, just to make sure it's synced up
// this also removes all the comments from the last time we edited it.
await npm.config.save(where)
const data = (await readFile(file, 'utf8').catch(() => '')).replace(/\r\n/g, '\n')

const data = (
await readFile(file, 'utf8').catch(() => '')
).replace(/\r\n/g, '\n')
const defData = Object.entries(defaults).reduce((str, [key, val]) => {
const obj = { [key]: val }
const i = ini.stringify(obj)
.replace(/\r\n/g, '\n') // normalizes output from ini.stringify
.replace(/\n$/m, '')
.replace(/^/g, '; ')
.replace(/\n/g, '\n; ')
Expand Down Expand Up @@ -179,9 +190,7 @@ ${defData}
`.split('\n').join(EOL)
await mkdirp(dirname(file))
await writeFile(file, tmpData, 'utf8')
await new Promise((res, rej) => {
editor(file, { editor: e }, (er) => er ? rej(er) : res())
})
await editor(file, { editor: e })
}

const publicVar = k => !/^(\/\/[^:]+:)?_/.test(k)
Expand Down
150 changes: 150 additions & 0 deletions tap-snapshots/test-lib-config.js-TAP.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/* 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/lib/config.js TAP config edit --global > should write global config file 1`] = `
;;;;
; npm globalconfig file: /etc/npmrc
; this is a simple ini-formatted file
; lines that start with semi-colons are comments
; run \`npm help 7 config\` for documentation of the various options
;
; Configs like \`@scope:registry\` map a scope to a given registry url.
;
; Configs like \`//<hostname>/:_authToken\` are auth that is restricted
; to the registry host specified.

init.author.name=Foo

;;;;
; all available options shown below with default values
;;;;


; init-author-name=
; init-version=1.0.0
; init.author.name=
; init.version=1.0.0

`

exports[`test/lib/config.js TAP config edit > should write config file 1`] = `
;;;;
; npm userconfig file: ~/.npmrc
; this is a simple ini-formatted file
; lines that start with semi-colons are comments
; run \`npm help 7 config\` for documentation of the various options
;
; Configs like \`@scope:registry\` map a scope to a given registry url.
;
; Configs like \`//<hostname>/:_authToken\` are auth that is restricted
; to the registry host specified.

//registry.npmjs.org/:_authToken=0000000
init.author.name=Foo
sign-git-commit=true

;;;;
; all available options shown below with default values
;;;;


; init-author-name=
; init-version=1.0.0
; init.author.name=
; init.version=1.0.0

`

exports[`test/lib/config.js TAP config edit > should write config file 2`] = `
;;;;
; npm userconfig file: ~/.npmrc
; this is a simple ini-formatted file
; lines that start with semi-colons are comments
; run \`npm help 7 config\` for documentation of the various options
;
; Configs like \`@scope:registry\` map a scope to a given registry url.
;
; Configs like \`//<hostname>/:_authToken\` are auth that is restricted
; to the registry host specified.



;;;;
; all available options shown below with default values
;;;;


; init-author-name=
; init-version=1.0.0
; init.author.name=
; init.version=1.0.0

`

exports[`test/lib/config.js TAP config get no args > should list configs on config get no args 1`] = `
; "cli" config from command line options

editor = "vi"
global = false
json = false
long = false

; node bin location = /path/to/node
; cwd = {CWD}
; HOME = ~/
; Run \`npm config ls -l\` to show all defaults.
`

exports[`test/lib/config.js TAP config list --long > should list all configs 1`] = `
; "default" config from default values

init-author-name = ""
init-version = "1.0.0"
init.author.name = ""
init.version = "1.0.0"

; "cli" config from command line options

editor = "vi"
global = false
json = false
long = true
`

exports[`test/lib/config.js TAP config list > should list configs 1`] = `
; "cli" config from command line options

editor = "vi"
global = false
json = false
long = false

; node bin location = /path/to/node
; cwd = {CWD}
; HOME = ~/
; Run \`npm config ls -l\` to show all defaults.
`

exports[`test/lib/config.js TAP config list overrides > should list overriden configs 1`] = `
; "cli" config from command line options

editor = "vi"
global = false
init.author.name = "Bar"
json = false
long = false

; "user" config from ~/.npmrc

; //private-reg.npmjs.org/:_authThoken = (protected) ; overridden by cli
; init.author.name = "Foo" ; overridden by cli

; node bin location = /path/to/node
; cwd = {CWD}
; HOME = ~/
; Run \`npm config ls -l\` to show all defaults.
`
Loading