178 lines
4.4 KiB
Go
178 lines
4.4 KiB
Go
package list
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/MakeNowJust/heredoc"
|
|
"github.com/cli/cli/v2/internal/tableprinter"
|
|
"github.com/cli/cli/v2/pkg/cmd/project/shared/client"
|
|
"github.com/cli/cli/v2/pkg/cmd/project/shared/format"
|
|
"github.com/cli/cli/v2/pkg/cmd/project/shared/queries"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
"github.com/cli/cli/v2/pkg/iostreams"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type listOpts struct {
|
|
limit int
|
|
web bool
|
|
owner string
|
|
closed bool
|
|
exporter cmdutil.Exporter
|
|
}
|
|
|
|
type listConfig struct {
|
|
client *queries.Client
|
|
opts listOpts
|
|
URLOpener func(string) error
|
|
io *iostreams.IOStreams
|
|
}
|
|
|
|
func NewCmdList(f *cmdutil.Factory, runF func(config listConfig) error) *cobra.Command {
|
|
opts := listOpts{}
|
|
listCmd := &cobra.Command{
|
|
Use: "list",
|
|
Short: "List the projects for an owner",
|
|
Example: heredoc.Doc(`
|
|
# List the current user's projects
|
|
$ gh project list
|
|
|
|
# List the projects for org github including closed projects
|
|
$ gh project list --owner github --closed
|
|
`),
|
|
Aliases: []string{"ls"},
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
client, err := client.New(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
URLOpener := func(url string) error {
|
|
return f.Browser.Browse(url)
|
|
}
|
|
|
|
config := listConfig{
|
|
client: client,
|
|
opts: opts,
|
|
URLOpener: URLOpener,
|
|
io: f.IOStreams,
|
|
}
|
|
|
|
// allow testing of the command without actually running it
|
|
if runF != nil {
|
|
return runF(config)
|
|
}
|
|
return runList(config)
|
|
},
|
|
}
|
|
listCmd.Flags().StringVar(&opts.owner, "owner", "", "Login of the owner")
|
|
listCmd.Flags().BoolVarP(&opts.closed, "closed", "", false, "Include closed projects")
|
|
listCmd.Flags().BoolVarP(&opts.web, "web", "w", false, "Open projects list in the browser")
|
|
cmdutil.AddFormatFlags(listCmd, &opts.exporter)
|
|
listCmd.Flags().IntVarP(&opts.limit, "limit", "L", queries.LimitDefault, "Maximum number of projects to fetch")
|
|
|
|
return listCmd
|
|
}
|
|
|
|
func runList(config listConfig) error {
|
|
if config.opts.web {
|
|
url, err := buildURL(config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := config.URLOpener(url); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if config.opts.owner == "" {
|
|
config.opts.owner = "@me"
|
|
}
|
|
canPrompt := config.io.CanPrompt()
|
|
owner, err := config.client.NewOwner(canPrompt, config.opts.owner)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
projects, err := config.client.Projects(config.opts.owner, owner.Type, config.opts.limit, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
projects = filterProjects(projects, config)
|
|
|
|
if config.opts.exporter != nil {
|
|
return config.opts.exporter.Write(config.io, projects)
|
|
}
|
|
|
|
return printResults(config, projects, owner.Login)
|
|
}
|
|
|
|
// TODO: support non-github.com hostnames
|
|
func buildURL(config listConfig) (string, error) {
|
|
var url string
|
|
if config.opts.owner == "@me" || config.opts.owner == "" {
|
|
owner, err := config.client.ViewerLoginName()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
url = fmt.Sprintf("https://github.com/users/%s/projects", owner)
|
|
} else {
|
|
_, ownerType, err := config.client.OwnerIDAndType(config.opts.owner)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if ownerType == queries.UserOwner {
|
|
url = fmt.Sprintf("https://github.com/users/%s/projects", config.opts.owner)
|
|
} else {
|
|
url = fmt.Sprintf("https://github.com/orgs/%s/projects", config.opts.owner)
|
|
}
|
|
}
|
|
|
|
if config.opts.closed {
|
|
return url + "?query=is%3Aclosed", nil
|
|
}
|
|
return url, nil
|
|
}
|
|
|
|
func filterProjects(nodes queries.Projects, config listConfig) queries.Projects {
|
|
filtered := queries.Projects{
|
|
Nodes: make([]queries.Project, 0, len(nodes.Nodes)),
|
|
TotalCount: nodes.TotalCount,
|
|
}
|
|
for _, project := range nodes.Nodes {
|
|
if !config.opts.closed && project.Closed {
|
|
continue
|
|
}
|
|
filtered.Nodes = append(filtered.Nodes, project)
|
|
}
|
|
return filtered
|
|
}
|
|
|
|
func printResults(config listConfig, projects queries.Projects, owner string) error {
|
|
if len(projects.Nodes) == 0 {
|
|
return cmdutil.NewNoResultsError(fmt.Sprintf("No projects found for %s", owner))
|
|
}
|
|
|
|
tp := tableprinter.New(config.io, tableprinter.WithHeader("Number", "Title", "State", "ID"))
|
|
|
|
cs := config.io.ColorScheme()
|
|
for _, p := range projects.Nodes {
|
|
tp.AddField(
|
|
strconv.Itoa(int(p.Number)),
|
|
tableprinter.WithTruncate(nil),
|
|
)
|
|
tp.AddField(p.Title)
|
|
tp.AddField(
|
|
format.ProjectState(p),
|
|
tableprinter.WithColor(cs.ColorFromString(format.ColorForProjectState(p))),
|
|
)
|
|
tp.AddField(p.ID, tableprinter.WithTruncate(nil))
|
|
tp.EndRow()
|
|
}
|
|
|
|
return tp.Render()
|
|
}
|