-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Credit: @chrisdickinson Credit: @zkat
- Loading branch information
Showing
3 changed files
with
267 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
'use strict' | ||
|
||
const BB = require('bluebird') | ||
|
||
const figgyPudding = require('figgy-pudding') | ||
const liborg = require('libnpm/org') | ||
const npmConfig = require('./config/figgy-config.js') | ||
const output = require('./utils/output.js') | ||
const otplease = require('./utils/otplease.js') | ||
const Table = require('cli-table3') | ||
|
||
module.exports = org | ||
|
||
org.subcommands = ['set', 'rm', 'ls'] | ||
|
||
org.usage = | ||
'npm org set orgname username [developer | admin | owner]\n' + | ||
'npm org rm orgname username\n' + | ||
'npm org ls orgname' | ||
|
||
const OrgConfig = figgyPudding({ | ||
json: {}, | ||
loglevel: {}, | ||
parseable: {}, | ||
silent: {} | ||
}) | ||
|
||
org.completion = function (opts, cb) { | ||
var argv = opts.conf.argv.remain | ||
if (argv.length === 2) { | ||
return cb(null, org.subcommands) | ||
} | ||
switch (argv[2]) { | ||
case 'ls': | ||
case 'add': | ||
case 'rm': | ||
case 'set': | ||
return cb(null, []) | ||
default: | ||
return cb(new Error(argv[2] + ' not recognized')) | ||
} | ||
} | ||
|
||
function UsageError () { | ||
throw Object.assign(new Error(org.usage), {code: 'EUSAGE'}) | ||
} | ||
|
||
function org ([cmd, orgname, username, role], cb) { | ||
otplease(npmConfig(), opts => { | ||
opts = OrgConfig(opts) | ||
switch (cmd) { | ||
case 'add': | ||
case 'set': | ||
return orgSet(orgname, username, role, opts) | ||
case 'rm': | ||
return orgRm(orgname, username, opts) | ||
case 'ls': | ||
return orgList(orgname, opts) | ||
default: | ||
UsageError() | ||
} | ||
}).then( | ||
x => cb(null, x), | ||
err => err.code === 'EUSAGE' ? err.message : err | ||
) | ||
} | ||
|
||
function orgSet (org, user, role, opts) { | ||
return liborg.set(org, user, role, opts).then(memDeets => { | ||
if (opts.json) { | ||
output(JSON.stringify(memDeets, null, 2)) | ||
} else if (opts.parseable) { | ||
output(['org', 'orgsize', 'user', 'role'].join('\t')) | ||
output([ | ||
memDeets.org.name, | ||
memDeets.org.size, | ||
memDeets.user, | ||
memDeets.role | ||
]) | ||
} else if (!opts.silent && opts.loglevel !== 'silent') { | ||
output(`Added ${memDeets.user} as ${memDeets.role} to ${memDeets.org.name}. You now ${memDeets.org.size} member${memDeets.org.size === 1 ? '' : 's'} in this org.`) | ||
} | ||
return memDeets | ||
}) | ||
} | ||
|
||
function orgRm (org, user, opts) { | ||
return liborg.rm(org, user, opts).then(() => { | ||
return liborg.ls(org, opts) | ||
}).then(roster => { | ||
user = user.replace(/^[~@]?/, '') | ||
org = org.replace(/^[~@]?/, '') | ||
const userCount = Object.keys(roster).length | ||
if (opts.json) { | ||
output(JSON.stringify({ | ||
user, | ||
org, | ||
userCount, | ||
deleted: true | ||
})) | ||
} else if (opts.parseable) { | ||
output(['user', 'org', 'userCount', 'deleted'].join('\t')) | ||
output([user, org, userCount, true].join('\t')) | ||
} else if (!opts.silent && opts.loglevel !== 'silent') { | ||
output(`Successfully removed ${user} from ${org}. You now have ${userCount} member${userCount === 1 ? '' : 's'} in this org.`) | ||
} | ||
}) | ||
} | ||
|
||
function orgList (org, opts) { | ||
return liborg.ls(org, opts).then(roster => { | ||
if (opts.json) { | ||
output(JSON.stringify(roster, null, 2)) | ||
} else if (opts.parseable) { | ||
output(['user', 'role'].join('\t')) | ||
Object.keys(roster).forEach(user => { | ||
output([user, roster[user]].join('\t')) | ||
}) | ||
} else if (!opts.silent && opts.loglevel !== 'silent') { | ||
const table = new Table({head: ['user', 'role']}) | ||
Object.keys(roster).sort().forEach(user => { | ||
table.push([user, roster[user]]) | ||
}) | ||
output(table.toString()) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
'use strict' | ||
|
||
var mr = require('npm-registry-mock') | ||
|
||
var test = require('tap').test | ||
var common = require('../common-tap.js') | ||
|
||
var server | ||
|
||
test('setup', function (t) { | ||
mr({port: common.port}, function (err, s) { | ||
t.ifError(err, 'registry mocked successfully') | ||
server = s | ||
t.end() | ||
}) | ||
}) | ||
|
||
const names = ['add', 'set'] | ||
const roles = ['developer', 'admin', 'owner'] | ||
|
||
names.forEach(function (name) { | ||
test('org ' + name + ' [orgname] [username]: defaults to developer', function (t) { | ||
const membershipData = { | ||
org: { | ||
name: 'myorg', | ||
size: 1 | ||
}, | ||
user: 'myuser', | ||
role: 'developer' | ||
} | ||
server.put('/-/org/myorg/user', JSON.stringify({ | ||
user: 'myuser' | ||
})).reply(200, membershipData) | ||
common.npm([ | ||
'org', 'add', 'myorg', 'myuser', | ||
'--json', | ||
'--registry', common.registry, | ||
'--loglevel', 'silent' | ||
], {}, function (err, code, stdout, stderr) { | ||
t.ifError(err, 'npm org') | ||
|
||
t.equal(code, 0, 'exited OK') | ||
t.equal(stderr, '', 'no error output') | ||
|
||
t.same(JSON.parse(stdout), membershipData) | ||
t.end() | ||
}) | ||
}) | ||
|
||
roles.forEach(function (role) { | ||
test('org ' + name + ' [orgname] [username]: accepts role ' + role, function (t) { | ||
const membershipData = { | ||
org: { | ||
name: 'myorg', | ||
size: 1 | ||
}, | ||
user: 'myuser', | ||
role: role | ||
} | ||
server.put('/-/org/myorg/user', JSON.stringify({ | ||
user: 'myuser' | ||
})).reply(200, membershipData) | ||
common.npm([ | ||
'org', name, 'myorg', 'myuser', | ||
'--json', | ||
'--registry', common.registry, | ||
'--loglevel', 'silent' | ||
], {}, function (err, code, stdout, stderr) { | ||
t.ifError(err, 'npm org') | ||
|
||
t.equal(code, 0, 'exited OK') | ||
t.equal(stderr, '', 'no error output') | ||
|
||
t.same(JSON.parse(stdout), membershipData) | ||
t.end() | ||
}) | ||
}) | ||
}) | ||
}) | ||
|
||
test('org rm [orgname] [username]', function (t) { | ||
const membershipData = { | ||
otheruser: 'admin' | ||
} | ||
server.delete('/-/org/myorg/user', JSON.stringify({ | ||
user: 'myuser' | ||
})).reply(204, {}) | ||
server.get('/-/org/myorg/user') | ||
.reply(200, membershipData) | ||
common.npm([ | ||
'org', 'rm', 'myorg', 'myuser', | ||
'--json', | ||
'--registry', common.registry, | ||
'--loglevel', 'silent' | ||
], {}, function (err, code, stdout, stderr) { | ||
t.ifError(err, 'npm org') | ||
|
||
t.equal(code, 0, 'exited OK') | ||
t.equal(stderr, '', 'no error output') | ||
t.deepEqual(JSON.parse(stdout), { | ||
user: 'myuser', | ||
org: 'myorg', | ||
deleted: true, | ||
userCount: 1 | ||
}, 'got useful info') | ||
t.end() | ||
}) | ||
}) | ||
|
||
test('org ls [orgname]', function (t) { | ||
const membershipData = { | ||
username: 'admin', | ||
username2: 'foo' | ||
} | ||
server.get('/-/org/myorg/user') | ||
.reply(200, membershipData) | ||
common.npm([ | ||
'org', 'ls', 'myorg', | ||
'--json', | ||
'--registry', common.registry, | ||
'--loglevel', 'silent' | ||
], {}, function (err, code, stdout, stderr) { | ||
t.ifError(err, 'npm org') | ||
t.equal(code, 0, 'exited OK') | ||
t.equal(stderr, '', 'no error output') | ||
t.same(JSON.parse(stdout), membershipData, 'outputs members') | ||
t.end() | ||
}) | ||
}) | ||
|
||
test('cleanup', function (t) { | ||
t.pass('cleaned up') | ||
server.done() | ||
server.close() | ||
t.end() | ||
}) |