team.js 4.3 KB

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