OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git / lib / cli / commands / group.js

258 lines · javascript ref:
/**
 * pgh group commands
 *
 * Subcommands: create, list, info, delete, add-repo, remove-repo, add-member, remove-member
 */

import { table, jsonOut, log, error } from '../output.js'

export async function groupCommand (client, sub, args, flags) {
  switch (sub) {
    case 'create':
      return groupCreate(client, args[0], flags)
    case 'list':
    case 'ls':
      return groupList(client, flags)
    case 'info':
      return groupInfo(client, args[0], flags)
    case 'delete':
      return groupDelete(client, args[0], flags)
    case 'add-repo':
      return groupAddRepo(client, args[0], args[1], flags)
    case 'remove-repo':
      return groupRemoveRepo(client, args[0], args[1], flags)
    case 'add-member':
      return groupAddMember(client, args[0], args[1], flags)
    case 'remove-member':
      return groupRemoveMember(client, args[0], args[1], flags)
    default:
      groupHelp()
  }
}

async function groupCreate (client, name, flags) {
  if (!name) error('Usage: pgh group create <name> [--description "..."]')

  const data = await client.post('/api/namespaces', {
    name,
    type: 'group',
    displayName: flags['display-name'] || flags.displayName || name,
    description: flags.description || flags.d || ''
  })

  if (flags.json) {
    jsonOut(data)
    return
  }

  if (data.error) {
    error(data.error)
    return
  }

  log(`\u2713 Created group: ${data.name}`)
  if (data.description) log(`  Description: ${data.description}`)
}

async function groupList (client, flags) {
  const namespaces = await client.get('/api/namespaces?type=group')

  if (flags.json) {
    jsonOut(namespaces)
    return
  }

  if (namespaces.length === 0) {
    log('No groups found.')
    return
  }

  table(namespaces, [
    { key: 'name', label: 'NAME', width: 25 },
    { key: 'displayName', label: 'DISPLAY NAME', width: 25 },
    { key: 'repoCount', label: 'REPOS' },
    { key: 'memberCount', label: 'MEMBERS' }
  ].map(col => {
    // Add computed fields
    return col
  }))

  // Since table doesn't support computed keys, format manually
  const header = 'NAME                      REPOS   MEMBERS  DESCRIPTION'
  const sep = '-'.repeat(header.length)
  console.log('')
  console.log(header)
  console.log(sep)
  for (const ns of namespaces) {
    const repos = ns.repos ? ns.repos.length : 0
    const members = ns.members ? ns.members.length : 0
    const desc = ns.description ? ns.description.slice(0, 30) : ''
    console.log(
      `${ns.name.padEnd(26)}${String(repos).padEnd(8)}${String(members).padEnd(9)}${desc}`
    )
  }
}

async function groupInfo (client, name, flags) {
  if (!name) error('Usage: pgh group info <name>')

  const ns = await client.get(`/api/namespaces/${encodeURIComponent(name)}`)

  if (flags.json) {
    jsonOut(ns)
    return
  }

  if (ns.error) {
    error(ns.error)
    return
  }

  log(`Name:         ${ns.name}`)
  log(`Display Name: ${ns.displayName}`)
  log(`Type:         ${ns.type}`)
  log(`Description:  ${ns.description || '-'}`)
  log(`Visibility:   ${ns.visibility}`)
  log(`Repos:        ${ns.repos.length}`)

  if (ns.repos.length > 0) {
    log('')
    log('Repositories:')
    for (const repo of ns.repos) {
      log(`  - ${repo}`)
    }
  }

  if (ns.members && ns.members.length > 0) {
    log('')
    log('Members:')
    for (const m of ns.members) {
      log(`  - ${m.userId} (${m.role})`)
    }
  }
}

async function groupDelete (client, name, flags) {
  if (!name) error('Usage: pgh group delete <name>')

  const data = await client.del(`/api/namespaces/${encodeURIComponent(name)}`)

  if (flags.json) {
    jsonOut(data)
    return
  }

  if (data.error) {
    error(data.error)
    return
  }

  log(`\u2713 Deleted group: ${name}`)
}

async function groupAddRepo (client, groupName, repoName, flags) {
  if (!groupName || !repoName) error('Usage: pgh group add-repo <group> <repo>')

  const data = await client.post(`/api/namespaces/${encodeURIComponent(groupName)}/repos`, {
    repoName
  })

  if (flags.json) {
    jsonOut(data)
    return
  }

  if (data.error) {
    error(data.error)
    return
  }

  log(`\u2713 Added ${repoName} to group ${groupName}`)
}

async function groupRemoveRepo (client, groupName, repoName, flags) {
  if (!groupName || !repoName) error('Usage: pgh group remove-repo <group> <repo>')

  const data = await client.del(`/api/namespaces/${encodeURIComponent(groupName)}/repos/${encodeURIComponent(repoName)}`)

  if (flags.json) {
    jsonOut(data)
    return
  }

  if (data.error) {
    error(data.error)
    return
  }

  log(`\u2713 Removed ${repoName} from group ${groupName}`)
}

async function groupAddMember (client, groupName, userId, flags) {
  if (!groupName || !userId) error('Usage: pgh group add-member <group> <user-id> [--role admin|member]')

  const role = flags.role || 'member'

  const data = await client.post(`/api/namespaces/${encodeURIComponent(groupName)}/members`, {
    userId,
    role
  })

  if (flags.json) {
    jsonOut(data)
    return
  }

  if (data.error) {
    error(data.error)
    return
  }

  log(`\u2713 Added ${userId} to group ${groupName} as ${role}`)
}

async function groupRemoveMember (client, groupName, userId, flags) {
  if (!groupName || !userId) error('Usage: pgh group remove-member <group> <user-id>')

  const data = await client.del(`/api/namespaces/${encodeURIComponent(groupName)}/members/${encodeURIComponent(userId)}`)

  if (flags.json) {
    jsonOut(data)
    return
  }

  if (data.error) {
    error(data.error)
    return
  }

  log(`\u2713 Removed ${userId} from group ${groupName}`)
}

export function groupHelp () {
  log(`Usage: pgh group <subcommand> [args] [flags]

Subcommands:
  create <name>                    Create a new group
  list                             List all groups
  info <name>                      Show group details
  delete <name>                    Delete empty group
  add-repo <group> <repo>          Add repo to group
  remove-repo <group> <repo>       Remove repo from group
  add-member <group> <user-id>     Add member to group
  remove-member <group> <user-id>  Remove member from group

Flags:
  --description TEXT    Group description (create)
  --display-name TEXT   Display name (create)
  --role admin|member   Member role (add-member, default: member)
  --json                Output as JSON

Examples:
  pgh group create holepunchto --description "Holepunch core repos"
  pgh group add-repo holepunchto hypercore
  pgh group add-member holepunchto user123 --role admin
  pgh group list
  pgh group info holepunchto`)
}