team.js 4.8 KB

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