1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
const columns = require('cli-columns')
const libteam = require('libnpmteam')
const otplease = require('../utils/otplease.js')
const BaseCommand = require('../base-command.js')
class Team extends BaseCommand {
static description = 'Manage organization teams and team memberships'
static name = 'team'
static usage = [
'create <scope:team> [--otp <otpcode>]',
'destroy <scope:team> [--otp <otpcode>]',
'add <scope:team> <user> [--otp <otpcode>]',
'rm <scope:team> <user> [--otp <otpcode>]',
'ls <scope>|<scope:team>',
]
static params = [
'registry',
'otp',
'parseable',
'json',
]
static ignoreImplicitWorkspace = false
async completion (opts) {
const { conf: { argv: { remain: argv } } } = opts
const subcommands = ['create', 'destroy', 'add', 'rm', 'ls']
if (argv.length === 2) {
return subcommands
}
if (subcommands.includes(argv[2])) {
return []
}
throw new Error(argv[2] + ' not recognized')
}
async exec ([cmd, entity = '', user = '']) {
// Entities are in the format <scope>:<team>
// XXX: "description" option to libnpmteam is used as a description of the
// team, but in npm's options, this is a boolean meaning "show the
// description in npm search output". Hence its being set to null here.
await otplease(this.npm, { ...this.npm.flatOptions }, opts => {
entity = entity.replace(/^@/, '')
switch (cmd) {
case 'create': return this.create(entity, opts)
case 'destroy': return this.destroy(entity, opts)
case 'add': return this.add(entity, user, opts)
case 'rm': return this.rm(entity, user, opts)
case 'ls': {
const match = entity.match(/[^:]+:.+/)
if (match) {
return this.listUsers(entity, opts)
} else {
return this.listTeams(entity, opts)
}
}
default:
throw this.usageError()
}
})
}
async create (entity, opts) {
await libteam.create(entity, opts)
if (opts.json) {
this.npm.output(JSON.stringify({
created: true,
team: entity,
}))
} else if (opts.parseable) {
this.npm.output(`${entity}\tcreated`)
} else if (!this.npm.silent) {
this.npm.output(`+@${entity}`)
}
}
async destroy (entity, opts) {
await libteam.destroy(entity, opts)
if (opts.json) {
this.npm.output(JSON.stringify({
deleted: true,
team: entity,
}))
} else if (opts.parseable) {
this.npm.output(`${entity}\tdeleted`)
} else if (!this.npm.silent) {
this.npm.output(`-@${entity}`)
}
}
async add (entity, user, opts) {
await libteam.add(user, entity, opts)
if (opts.json) {
this.npm.output(JSON.stringify({
added: true,
team: entity,
user,
}))
} else if (opts.parseable) {
this.npm.output(`${user}\t${entity}\tadded`)
} else if (!this.npm.silent) {
this.npm.output(`${user} added to @${entity}`)
}
}
async rm (entity, user, opts) {
await libteam.rm(user, entity, opts)
if (opts.json) {
this.npm.output(JSON.stringify({
removed: true,
team: entity,
user,
}))
} else if (opts.parseable) {
this.npm.output(`${user}\t${entity}\tremoved`)
} else if (!this.npm.silent) {
this.npm.output(`${user} removed from @${entity}`)
}
}
async listUsers (entity, opts) {
const users = (await libteam.lsUsers(entity, opts)).sort()
if (opts.json) {
this.npm.output(JSON.stringify(users, null, 2))
} else if (opts.parseable) {
this.npm.output(users.join('\n'))
} else if (!this.npm.silent) {
const plural = users.length === 1 ? '' : 's'
const more = users.length === 0 ? '' : ':\n'
this.npm.output(`\n@${entity} has ${users.length} user${plural}${more}`)
this.npm.output(columns(users, { padding: 1 }))
}
}
async listTeams (entity, opts) {
const teams = (await libteam.lsTeams(entity, opts)).sort()
if (opts.json) {
this.npm.output(JSON.stringify(teams, null, 2))
} else if (opts.parseable) {
this.npm.output(teams.join('\n'))
} else if (!this.npm.silent) {
const plural = teams.length === 1 ? '' : 's'
const more = teams.length === 0 ? '' : ':\n'
this.npm.output(`\n@${entity} has ${teams.length} team${plural}${more}`)
this.npm.output(columns(teams.map(t => `@${t}`), { padding: 1 }))
}
}
}
module.exports = Team
|