Remove project JSON formatting objects (#8541)
This commit is contained in:
parent
57f6787c15
commit
cf483770c9
21 changed files with 417 additions and 625 deletions
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -104,7 +103,7 @@ func runClose(config closeConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.UpdateProjectV2.ProjectV2)
|
||||
return config.opts.exporter.Write(config.io, query.UpdateProjectV2.ProjectV2)
|
||||
}
|
||||
|
||||
return printResults(config, query.UpdateProjectV2.ProjectV2)
|
||||
|
|
@ -132,8 +131,3 @@ func printResults(config closeConfig, project queries.Project) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "%s\n", project.URL)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config closeConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -114,7 +113,7 @@ func runCopy(config copyConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.CopyProjectV2.ProjectV2)
|
||||
return config.opts.exporter.Write(config.io, query.CopyProjectV2.ProjectV2)
|
||||
}
|
||||
|
||||
return printResults(config, query.CopyProjectV2.ProjectV2)
|
||||
|
|
@ -142,8 +141,3 @@ func printResults(config copyConfig, project queries.Project) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "%s\n", project.URL)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config copyConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -86,7 +85,7 @@ func runCreate(config createConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.CreateProjectV2.ProjectV2)
|
||||
return config.opts.exporter.Write(config.io, query.CreateProjectV2.ProjectV2)
|
||||
}
|
||||
|
||||
return printResults(config, query.CreateProjectV2.ProjectV2)
|
||||
|
|
@ -113,8 +112,3 @@ func printResults(config createConfig, project queries.Project) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "%s\n", project.URL)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config createConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -97,7 +96,7 @@ func runDelete(config deleteConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.DeleteProject.Project)
|
||||
return config.opts.exporter.Write(config.io, query.DeleteProject.Project)
|
||||
}
|
||||
|
||||
return printResults(config, query.DeleteProject.Project)
|
||||
|
|
@ -124,8 +123,3 @@ func printResults(config deleteConfig, project queries.Project) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Deleted project %d\n", project.Number)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config deleteConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -111,7 +110,7 @@ func runEdit(config editConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.UpdateProjectV2.ProjectV2)
|
||||
return config.opts.exporter.Write(config.io, query.UpdateProjectV2.ProjectV2)
|
||||
}
|
||||
|
||||
return printResults(config, query.UpdateProjectV2.ProjectV2)
|
||||
|
|
@ -153,8 +152,3 @@ func printResults(config editConfig, project queries.Project) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "%s\n", project.URL)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config editConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -114,7 +113,7 @@ func runCreateField(config createFieldConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.CreateProjectV2Field.Field)
|
||||
return config.opts.exporter.Write(config.io, query.CreateProjectV2Field.Field)
|
||||
}
|
||||
|
||||
return printResults(config, query.CreateProjectV2Field.Field)
|
||||
|
|
@ -151,8 +150,3 @@ func printResults(config createFieldConfig, field queries.ProjectField) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Created field\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config createFieldConfig, field queries.ProjectField) error {
|
||||
projectFieldJSON := format.JSONProjectField(field)
|
||||
return config.opts.exporter.Write(config.io, projectFieldJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"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"
|
||||
|
|
@ -71,7 +70,7 @@ func runDeleteField(config deleteFieldConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.DeleteProjectV2Field.Field)
|
||||
return config.opts.exporter.Write(config.io, query.DeleteProjectV2Field.Field)
|
||||
}
|
||||
|
||||
return printResults(config, query.DeleteProjectV2Field.Field)
|
||||
|
|
@ -93,8 +92,3 @@ func printResults(config deleteFieldConfig, field queries.ProjectField) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Deleted field\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config deleteFieldConfig, field queries.ProjectField) error {
|
||||
projectFieldJSON := format.JSONProjectField(field)
|
||||
return config.opts.exporter.Write(config.io, projectFieldJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"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"
|
||||
|
|
@ -95,7 +94,7 @@ func runList(config listConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, project)
|
||||
return config.opts.exporter.Write(config.io, project.Fields)
|
||||
}
|
||||
|
||||
return printResults(config, project.Fields.Nodes, owner.Login)
|
||||
|
|
@ -117,8 +116,3 @@ func printResults(config listConfig, fields []queries.ProjectField, login string
|
|||
|
||||
return tp.Render()
|
||||
}
|
||||
|
||||
func printJSON(config listConfig, project *queries.Project) error {
|
||||
projectsJSON := format.JSONProjectFields(project)
|
||||
return config.opts.exporter.Write(config.io, projectsJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -108,7 +107,7 @@ func runAddItem(config addItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.CreateProjectItem.ProjectV2Item)
|
||||
return config.opts.exporter.Write(config.io, query.CreateProjectItem.ProjectV2Item)
|
||||
}
|
||||
|
||||
return printResults(config, query.CreateProjectItem.ProjectV2Item)
|
||||
|
|
@ -132,8 +131,3 @@ func printResults(config addItemConfig, item queries.ProjectItem) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Added item\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config addItemConfig, item queries.ProjectItem) error {
|
||||
projectItemJSON := format.JSONProjectItem(item)
|
||||
return config.opts.exporter.Write(config.io, projectItemJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -110,7 +109,7 @@ func runArchiveItem(config archiveItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.UnarchiveProjectItem.ProjectV2Item)
|
||||
return config.opts.exporter.Write(config.io, query.UnarchiveProjectItem.ProjectV2Item)
|
||||
}
|
||||
|
||||
return printResults(config, query.UnarchiveProjectItem.ProjectV2Item)
|
||||
|
|
@ -122,7 +121,7 @@ func runArchiveItem(config archiveItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.ArchiveProjectItem.ProjectV2Item)
|
||||
return config.opts.exporter.Write(config.io, query.ArchiveProjectItem.ProjectV2Item)
|
||||
}
|
||||
|
||||
return printResults(config, query.ArchiveProjectItem.ProjectV2Item)
|
||||
|
|
@ -159,8 +158,3 @@ func printResults(config archiveItemConfig, item queries.ProjectItem) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Archived item\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config archiveItemConfig, item queries.ProjectItem) error {
|
||||
projectItemJSON := format.JSONProjectItem(item)
|
||||
return config.opts.exporter.Write(config.io, projectItemJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -104,7 +103,7 @@ func runCreateItem(config createItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.CreateProjectDraftItem.ProjectV2Item)
|
||||
return config.opts.exporter.Write(config.io, query.CreateProjectDraftItem.ProjectV2Item)
|
||||
}
|
||||
|
||||
return printResults(config, query.CreateProjectDraftItem.ProjectV2Item)
|
||||
|
|
@ -128,8 +127,3 @@ func printResults(config createItemConfig, item queries.ProjectItem) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Created item\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config createItemConfig, item queries.ProjectItem) error {
|
||||
projectItemJSON := format.JSONProjectItem(item)
|
||||
return config.opts.exporter.Write(config.io, projectItemJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -219,11 +218,6 @@ func printDraftIssueResults(config editItemConfig, item queries.DraftIssue) erro
|
|||
return err
|
||||
}
|
||||
|
||||
func printDraftIssueJSON(config editItemConfig, item queries.DraftIssue) error {
|
||||
projectDraftItemJSON := format.JSONProjectDraftIssue(item)
|
||||
return config.opts.exporter.Write(config.io, projectDraftItemJSON)
|
||||
}
|
||||
|
||||
func printItemResults(config editItemConfig, item *queries.ProjectItem) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
|
|
@ -232,11 +226,6 @@ func printItemResults(config editItemConfig, item *queries.ProjectItem) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func printItemJSON(config editItemConfig, item *queries.ProjectItem) error {
|
||||
projectItemJSON := format.JSONProjectItem(*item)
|
||||
return config.opts.exporter.Write(config.io, projectItemJSON)
|
||||
}
|
||||
|
||||
func clearItemFieldValue(config editItemConfig) error {
|
||||
if err := fieldIdAndProjectIdPresence(config); err != nil {
|
||||
return err
|
||||
|
|
@ -248,7 +237,7 @@ func clearItemFieldValue(config editItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printItemJSON(config, &query.Clear.Item)
|
||||
return config.opts.exporter.Write(config.io, &query.Clear.Item)
|
||||
}
|
||||
|
||||
return printItemResults(config, &query.Clear.Item)
|
||||
|
|
@ -267,7 +256,7 @@ func updateDraftIssue(config editItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printDraftIssueJSON(config, query.UpdateProjectV2DraftIssue.DraftIssue)
|
||||
return config.opts.exporter.Write(config.io, query.UpdateProjectV2DraftIssue.DraftIssue)
|
||||
}
|
||||
|
||||
return printDraftIssueResults(config, query.UpdateProjectV2DraftIssue.DraftIssue)
|
||||
|
|
@ -294,7 +283,7 @@ func updateItemValues(config editItemConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printItemJSON(config, &query.Update.Item)
|
||||
return config.opts.exporter.Write(config.io, &query.Update.Item)
|
||||
}
|
||||
|
||||
return printItemResults(config, &query.Update.Item)
|
||||
|
|
|
|||
|
|
@ -546,6 +546,7 @@ func TestRunItemEdit_JSON(t *testing.T) {
|
|||
"data": map[string]interface{}{
|
||||
"updateProjectV2DraftIssue": map[string]interface{}{
|
||||
"draftIssue": map[string]interface{}{
|
||||
"id": "DI_item_id",
|
||||
"title": "a title",
|
||||
"body": "a new body",
|
||||
},
|
||||
|
|
@ -571,6 +572,6 @@ func TestRunItemEdit_JSON(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.JSONEq(
|
||||
t,
|
||||
`{"id":"","title":"a title","body":"a new body","type":"DraftIssue"}`,
|
||||
`{"id":"DI_item_id","title":"a title","body":"a new body","type":"DraftIssue"}`,
|
||||
stdout.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"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"
|
||||
|
|
@ -94,7 +93,7 @@ func runList(config listConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, project)
|
||||
return config.opts.exporter.Write(config.io, project.DetailedItems())
|
||||
}
|
||||
|
||||
return printResults(config, project.Items.Nodes, owner.Login)
|
||||
|
|
@ -122,8 +121,3 @@ func printResults(config listConfig, items []queries.ProjectItem, login string)
|
|||
|
||||
return tp.Render()
|
||||
}
|
||||
|
||||
func printJSON(config listConfig, project *queries.Project) error {
|
||||
projectDetailedItemsJSON := format.JSONProjectDetailedItems(project)
|
||||
return config.opts.exporter.Write(config.io, projectDetailedItemsJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,14 +97,14 @@ func runList(config listConfig) error {
|
|||
return err
|
||||
}
|
||||
|
||||
projects, totalCount, err := config.client.Projects(config.opts.owner, owner.Type, config.opts.limit, false)
|
||||
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 printJSON(config, projects, totalCount)
|
||||
return config.opts.exporter.Write(config.io, projects)
|
||||
}
|
||||
|
||||
return printResults(config, projects, owner.Login)
|
||||
|
|
@ -138,26 +138,29 @@ func buildURL(config listConfig) (string, error) {
|
|||
return url, nil
|
||||
}
|
||||
|
||||
func filterProjects(nodes []queries.Project, config listConfig) []queries.Project {
|
||||
projects := make([]queries.Project, 0, len(nodes))
|
||||
for _, p := range nodes {
|
||||
if !config.opts.closed && p.Closed {
|
||||
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
|
||||
}
|
||||
projects = append(projects, p)
|
||||
filtered.Nodes = append(filtered.Nodes, project)
|
||||
}
|
||||
return projects
|
||||
return filtered
|
||||
}
|
||||
|
||||
func printResults(config listConfig, projects []queries.Project, owner string) error {
|
||||
if len(projects) == 0 {
|
||||
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 {
|
||||
for _, p := range projects.Nodes {
|
||||
tp.AddField(
|
||||
strconv.Itoa(int(p.Number)),
|
||||
tableprinter.WithTruncate(nil),
|
||||
|
|
@ -173,8 +176,3 @@ func printResults(config listConfig, projects []queries.Project, owner string) e
|
|||
|
||||
return tp.Render()
|
||||
}
|
||||
|
||||
func printJSON(config listConfig, projects []queries.Project, totalCount int) error {
|
||||
projectsJSON := format.JSONProjects(projects, totalCount)
|
||||
return config.opts.exporter.Write(config.io, projectsJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -108,7 +107,7 @@ func runMarkTemplate(config markTemplateConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, *project)
|
||||
return config.opts.exporter.Write(config.io, *project)
|
||||
}
|
||||
|
||||
return printResults(config, query.TemplateProject.Project)
|
||||
|
|
@ -121,7 +120,7 @@ func runMarkTemplate(config markTemplateConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, query.TemplateProject.Project)
|
||||
return config.opts.exporter.Write(config.io, query.TemplateProject.Project)
|
||||
}
|
||||
|
||||
return printResults(config, query.TemplateProject.Project)
|
||||
|
|
@ -164,8 +163,3 @@ func printResults(config markTemplateConfig, project queries.Project) error {
|
|||
_, err := fmt.Fprintf(config.io.Out, "Marked project %d as a template.\n", project.Number)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config markTemplateConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,386 +0,0 @@
|
|||
package format
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cli/cli/v2/pkg/cmd/project/shared/queries"
|
||||
)
|
||||
|
||||
// JSONProject serializes a Project to JSON.
|
||||
func JSONProject(project queries.Project) ProjectJSON {
|
||||
return ProjectJSON{
|
||||
Number: project.Number,
|
||||
URL: project.URL,
|
||||
ShortDescription: project.ShortDescription,
|
||||
Public: project.Public,
|
||||
Closed: project.Closed,
|
||||
// The Template field is commented out due to https://github.com/cli/cli/issues/8103.
|
||||
// The Template field does not exist on GHES 3.8 and older, once GHES 3.8 gets
|
||||
// deprecated on 2024-03-07 we can start populating this field again.
|
||||
// Template: project.Template,
|
||||
Title: project.Title,
|
||||
ID: project.ID,
|
||||
Readme: project.Readme,
|
||||
Items: struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}{
|
||||
TotalCount: project.Items.TotalCount,
|
||||
},
|
||||
Fields: struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}{
|
||||
TotalCount: project.Fields.TotalCount,
|
||||
},
|
||||
Owner: struct {
|
||||
Type string `json:"type"`
|
||||
Login string `json:"login"`
|
||||
}{
|
||||
Type: project.OwnerType(),
|
||||
Login: project.OwnerLogin(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// JSONProjects serializes a slice of Projects to JSON.
|
||||
// JSON fields are `totalCount` and `projects`.
|
||||
func JSONProjects(projects []queries.Project, totalCount int) ProjectsJSON {
|
||||
var result []ProjectJSON
|
||||
for _, p := range projects {
|
||||
result = append(result, ProjectJSON{
|
||||
Number: p.Number,
|
||||
URL: p.URL,
|
||||
ShortDescription: p.ShortDescription,
|
||||
Public: p.Public,
|
||||
Closed: p.Closed,
|
||||
// The Template field is commented out due to https://github.com/cli/cli/issues/8103.
|
||||
// The Template field does not exist on GHES 3.8 and older, once GHES 3.8 gets
|
||||
// deprecated on 2024-03-07 we can start populating this field again.
|
||||
// Template: p.Template,
|
||||
Title: p.Title,
|
||||
ID: p.ID,
|
||||
Readme: p.Readme,
|
||||
Items: struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}{
|
||||
TotalCount: p.Items.TotalCount,
|
||||
},
|
||||
Fields: struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}{
|
||||
TotalCount: p.Fields.TotalCount,
|
||||
},
|
||||
Owner: struct {
|
||||
Type string `json:"type"`
|
||||
Login string `json:"login"`
|
||||
}{
|
||||
Type: p.OwnerType(),
|
||||
Login: p.OwnerLogin(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return ProjectsJSON{
|
||||
Projects: result,
|
||||
TotalCount: totalCount,
|
||||
}
|
||||
}
|
||||
|
||||
type ProjectJSON struct {
|
||||
Number int32 `json:"number"`
|
||||
URL string `json:"url"`
|
||||
ShortDescription string `json:"shortDescription"`
|
||||
Public bool `json:"public"`
|
||||
Closed bool `json:"closed"`
|
||||
// The Template field is commented out due to https://github.com/cli/cli/issues/8103.
|
||||
// The Template field does not exist on GHES 3.8 and older, once GHES 3.8 gets
|
||||
// deprecated on 2024-03-07 we can start populating this field again.
|
||||
// Template bool `json:"template"`
|
||||
Title string `json:"title"`
|
||||
ID string `json:"id"`
|
||||
Readme string `json:"readme"`
|
||||
Items struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
} `graphql:"items(first: 100)" json:"items"`
|
||||
Fields struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
} `graphql:"fields(first:100)" json:"fields"`
|
||||
Owner struct {
|
||||
Type string `json:"type"`
|
||||
Login string `json:"login"`
|
||||
} `json:"owner"`
|
||||
}
|
||||
|
||||
type ProjectsJSON struct {
|
||||
Projects []ProjectJSON `json:"projects"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
|
||||
// JSONProjectField serializes a ProjectField to JSON.
|
||||
func JSONProjectField(field queries.ProjectField) ProjectFieldJSON {
|
||||
val := ProjectFieldJSON{
|
||||
ID: field.ID(),
|
||||
Name: field.Name(),
|
||||
Type: field.Type(),
|
||||
}
|
||||
for _, o := range field.Options() {
|
||||
val.Options = append(val.Options, SingleSelectOptionJSON{
|
||||
Name: o.Name,
|
||||
ID: o.ID,
|
||||
})
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// JSONProjectFields serializes a slice of ProjectFields to JSON.
|
||||
// JSON fields are `totalCount` and `fields`.
|
||||
func JSONProjectFields(project *queries.Project) ProjectFieldsJSON {
|
||||
var result []ProjectFieldJSON
|
||||
for _, f := range project.Fields.Nodes {
|
||||
val := ProjectFieldJSON{
|
||||
ID: f.ID(),
|
||||
Name: f.Name(),
|
||||
Type: f.Type(),
|
||||
}
|
||||
for _, o := range f.Options() {
|
||||
val.Options = append(val.Options, SingleSelectOptionJSON{
|
||||
Name: o.Name,
|
||||
ID: o.ID,
|
||||
})
|
||||
}
|
||||
|
||||
result = append(result, val)
|
||||
}
|
||||
|
||||
return ProjectFieldsJSON{
|
||||
Fields: result,
|
||||
TotalCount: project.Fields.TotalCount,
|
||||
}
|
||||
}
|
||||
|
||||
type ProjectFieldJSON struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Options []SingleSelectOptionJSON `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
type ProjectFieldsJSON struct {
|
||||
Fields []ProjectFieldJSON `json:"fields"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
|
||||
type SingleSelectOptionJSON struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// JSONProjectItem serializes a ProjectItem to JSON.
|
||||
func JSONProjectItem(item queries.ProjectItem) ProjectItemJSON {
|
||||
return ProjectItemJSON{
|
||||
ID: item.ID(),
|
||||
Title: item.Title(),
|
||||
Body: item.Body(),
|
||||
Type: item.Type(),
|
||||
URL: item.URL(),
|
||||
}
|
||||
}
|
||||
|
||||
type ProjectItemJSON struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// JSONProjectDraftIssue serializes a DraftIssue to JSON.
|
||||
// This is needed because the field for
|
||||
// https://docs.github.com/en/graphql/reference/mutations#updateprojectv2draftissue
|
||||
// is a DraftIssue https://docs.github.com/en/graphql/reference/objects#draftissue
|
||||
// and not a ProjectV2Item https://docs.github.com/en/graphql/reference/objects#projectv2item
|
||||
func JSONProjectDraftIssue(item queries.DraftIssue) DraftIssueJSON {
|
||||
|
||||
return DraftIssueJSON{
|
||||
ID: item.ID,
|
||||
Title: item.Title,
|
||||
Body: item.Body,
|
||||
Type: "DraftIssue",
|
||||
}
|
||||
}
|
||||
|
||||
type DraftIssueJSON struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func projectItemContent(p queries.ProjectItem) any {
|
||||
switch p.Content.TypeName {
|
||||
case "DraftIssue":
|
||||
return struct {
|
||||
Type string `json:"type"`
|
||||
Body string `json:"body"`
|
||||
Title string `json:"title"`
|
||||
}{
|
||||
Type: p.Type(),
|
||||
Body: p.Body(),
|
||||
Title: p.Title(),
|
||||
}
|
||||
case "Issue":
|
||||
return struct {
|
||||
Type string `json:"type"`
|
||||
Body string `json:"body"`
|
||||
Title string `json:"title"`
|
||||
Number int `json:"number"`
|
||||
Repository string `json:"repository"`
|
||||
URL string `json:"url"`
|
||||
}{
|
||||
Type: p.Type(),
|
||||
Body: p.Body(),
|
||||
Title: p.Title(),
|
||||
Number: p.Number(),
|
||||
Repository: p.Repo(),
|
||||
URL: p.URL(),
|
||||
}
|
||||
case "PullRequest":
|
||||
return struct {
|
||||
Type string `json:"type"`
|
||||
Body string `json:"body"`
|
||||
Title string `json:"title"`
|
||||
Number int `json:"number"`
|
||||
Repository string `json:"repository"`
|
||||
URL string `json:"url"`
|
||||
}{
|
||||
Type: p.Type(),
|
||||
Body: p.Body(),
|
||||
Title: p.Title(),
|
||||
Number: p.Number(),
|
||||
Repository: p.Repo(),
|
||||
URL: p.URL(),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func projectFieldValueData(v queries.FieldValueNodes) any {
|
||||
switch v.Type {
|
||||
case "ProjectV2ItemFieldDateValue":
|
||||
return v.ProjectV2ItemFieldDateValue.Date
|
||||
case "ProjectV2ItemFieldIterationValue":
|
||||
return struct {
|
||||
Title string `json:"title"`
|
||||
StartDate string `json:"startDate"`
|
||||
Duration int `json:"duration"`
|
||||
}{
|
||||
Title: v.ProjectV2ItemFieldIterationValue.Title,
|
||||
StartDate: v.ProjectV2ItemFieldIterationValue.StartDate,
|
||||
Duration: v.ProjectV2ItemFieldIterationValue.Duration,
|
||||
}
|
||||
case "ProjectV2ItemFieldNumberValue":
|
||||
return v.ProjectV2ItemFieldNumberValue.Number
|
||||
case "ProjectV2ItemFieldSingleSelectValue":
|
||||
return v.ProjectV2ItemFieldSingleSelectValue.Name
|
||||
case "ProjectV2ItemFieldTextValue":
|
||||
return v.ProjectV2ItemFieldTextValue.Text
|
||||
case "ProjectV2ItemFieldMilestoneValue":
|
||||
return struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
DueOn string `json:"dueOn"`
|
||||
}{
|
||||
Title: v.ProjectV2ItemFieldMilestoneValue.Milestone.Title,
|
||||
Description: v.ProjectV2ItemFieldMilestoneValue.Milestone.Description,
|
||||
DueOn: v.ProjectV2ItemFieldMilestoneValue.Milestone.DueOn,
|
||||
}
|
||||
case "ProjectV2ItemFieldLabelValue":
|
||||
names := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldLabelValue.Labels.Nodes {
|
||||
names = append(names, p.Name)
|
||||
}
|
||||
return names
|
||||
case "ProjectV2ItemFieldPullRequestValue":
|
||||
urls := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldPullRequestValue.PullRequests.Nodes {
|
||||
urls = append(urls, p.Url)
|
||||
}
|
||||
return urls
|
||||
case "ProjectV2ItemFieldRepositoryValue":
|
||||
return v.ProjectV2ItemFieldRepositoryValue.Repository.Url
|
||||
case "ProjectV2ItemFieldUserValue":
|
||||
logins := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldUserValue.Users.Nodes {
|
||||
logins = append(logins, p.Login)
|
||||
}
|
||||
return logins
|
||||
case "ProjectV2ItemFieldReviewerValue":
|
||||
names := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldReviewerValue.Reviewers.Nodes {
|
||||
if p.Type == "Team" {
|
||||
names = append(names, p.Team.Name)
|
||||
} else if p.Type == "User" {
|
||||
names = append(names, p.User.Login)
|
||||
}
|
||||
}
|
||||
return names
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// serialize creates a map from field to field values
|
||||
func serializeProjectWithItems(project *queries.Project) []map[string]any {
|
||||
fields := make(map[string]string)
|
||||
|
||||
// make a map of fields by ID
|
||||
for _, f := range project.Fields.Nodes {
|
||||
fields[f.ID()] = camelCase(f.Name())
|
||||
}
|
||||
itemsSlice := make([]map[string]any, 0)
|
||||
|
||||
// for each value, look up the name by ID
|
||||
// and set the value to the field value
|
||||
for _, i := range project.Items.Nodes {
|
||||
o := make(map[string]any)
|
||||
o["id"] = i.Id
|
||||
o["content"] = projectItemContent(i)
|
||||
for _, v := range i.FieldValues.Nodes {
|
||||
id := v.ID()
|
||||
value := projectFieldValueData(v)
|
||||
|
||||
o[fields[id]] = value
|
||||
}
|
||||
itemsSlice = append(itemsSlice, o)
|
||||
}
|
||||
return itemsSlice
|
||||
}
|
||||
|
||||
// JSONProjectWithItems returns a detailed JSON representation of project items.
|
||||
// JSON fields are `totalCount` and `items`.
|
||||
func JSONProjectDetailedItems(project *queries.Project) ProjectDetailedItems {
|
||||
items := serializeProjectWithItems(project)
|
||||
return ProjectDetailedItems{
|
||||
Items: items,
|
||||
TotalCount: project.Items.TotalCount,
|
||||
}
|
||||
}
|
||||
|
||||
type ProjectDetailedItems struct {
|
||||
Items []map[string]any `json:"items"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
|
||||
// camelCase converts a string to camelCase, which is useful for turning Go field names to JSON keys.
|
||||
func camelCase(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(s) == 1 {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
return strings.ToLower(s[0:1]) + s[1:]
|
||||
}
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
package format
|
||||
package queries
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/pkg/cmd/project/shared/queries"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Regression test from before ExportData was implemented.
|
||||
func TestJSONProject_User(t *testing.T) {
|
||||
project := queries.Project{
|
||||
project := Project{
|
||||
ID: "123",
|
||||
Number: 2,
|
||||
URL: "a url",
|
||||
|
|
@ -23,14 +22,15 @@ func TestJSONProject_User(t *testing.T) {
|
|||
project.Fields.TotalCount = 2
|
||||
project.Owner.TypeName = "User"
|
||||
project.Owner.User.Login = "monalisa"
|
||||
b, err := json.Marshal(JSONProject(project))
|
||||
b, err := json.Marshal(project.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"number":2,"url":"a url","shortDescription":"short description","public":true,"closed":false,"title":"","id":"123","readme":"readme","items":{"totalCount":1},"fields":{"totalCount":2},"owner":{"type":"User","login":"monalisa"}}`, string(b))
|
||||
assert.JSONEq(t, `{"number":2,"url":"a url","shortDescription":"short description","public":true,"closed":false,"title":"","id":"123","readme":"readme","items":{"totalCount":1},"fields":{"totalCount":2},"owner":{"type":"User","login":"monalisa"}}`, string(b))
|
||||
}
|
||||
|
||||
// Regression test from before ExportData was implemented.
|
||||
func TestJSONProject_Org(t *testing.T) {
|
||||
project := queries.Project{
|
||||
project := Project{
|
||||
ID: "123",
|
||||
Number: 2,
|
||||
URL: "a url",
|
||||
|
|
@ -43,14 +43,15 @@ func TestJSONProject_Org(t *testing.T) {
|
|||
project.Fields.TotalCount = 2
|
||||
project.Owner.TypeName = "Organization"
|
||||
project.Owner.Organization.Login = "github"
|
||||
b, err := json.Marshal(JSONProject(project))
|
||||
b, err := json.Marshal(project.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"number":2,"url":"a url","shortDescription":"short description","public":true,"closed":false,"title":"","id":"123","readme":"readme","items":{"totalCount":1},"fields":{"totalCount":2},"owner":{"type":"Organization","login":"github"}}`, string(b))
|
||||
assert.JSONEq(t, `{"number":2,"url":"a url","shortDescription":"short description","public":true,"closed":false,"title":"","id":"123","readme":"readme","items":{"totalCount":1},"fields":{"totalCount":2},"owner":{"type":"Organization","login":"github"}}`, string(b))
|
||||
}
|
||||
|
||||
// Regression test from before ExportData was implemented.
|
||||
func TestJSONProjects(t *testing.T) {
|
||||
userProject := queries.Project{
|
||||
userProject := Project{
|
||||
ID: "123",
|
||||
Number: 2,
|
||||
URL: "a url",
|
||||
|
|
@ -64,7 +65,7 @@ func TestJSONProjects(t *testing.T) {
|
|||
userProject.Owner.TypeName = "User"
|
||||
userProject.Owner.User.Login = "monalisa"
|
||||
|
||||
orgProject := queries.Project{
|
||||
orgProject := Project{
|
||||
ID: "123",
|
||||
Number: 2,
|
||||
URL: "a url",
|
||||
|
|
@ -77,34 +78,38 @@ func TestJSONProjects(t *testing.T) {
|
|||
orgProject.Fields.TotalCount = 2
|
||||
orgProject.Owner.TypeName = "Organization"
|
||||
orgProject.Owner.Organization.Login = "github"
|
||||
projectsJSON := JSONProjects([]queries.Project{userProject, orgProject}, 2)
|
||||
b, err := json.Marshal(projectsJSON)
|
||||
|
||||
projects := Projects{
|
||||
Nodes: []Project{userProject, orgProject},
|
||||
TotalCount: 2,
|
||||
}
|
||||
b, err := json.Marshal(projects.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(
|
||||
assert.JSONEq(
|
||||
t,
|
||||
`{"projects":[{"number":2,"url":"a url","shortDescription":"short description","public":true,"closed":false,"title":"","id":"123","readme":"readme","items":{"totalCount":1},"fields":{"totalCount":2},"owner":{"type":"User","login":"monalisa"}},{"number":2,"url":"a url","shortDescription":"short description","public":true,"closed":false,"title":"","id":"123","readme":"readme","items":{"totalCount":1},"fields":{"totalCount":2},"owner":{"type":"Organization","login":"github"}}],"totalCount":2}`,
|
||||
string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectField_FieldType(t *testing.T) {
|
||||
field := queries.ProjectField{}
|
||||
field := ProjectField{}
|
||||
field.TypeName = "ProjectV2Field"
|
||||
field.Field.ID = "123"
|
||||
field.Field.Name = "name"
|
||||
|
||||
b, err := json.Marshal(JSONProjectField(field))
|
||||
b, err := json.Marshal(field.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","name":"name","type":"ProjectV2Field"}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectField_SingleSelectType(t *testing.T) {
|
||||
field := queries.ProjectField{}
|
||||
field := ProjectField{}
|
||||
field.TypeName = "ProjectV2SingleSelectField"
|
||||
field.SingleSelectField.ID = "123"
|
||||
field.SingleSelectField.Name = "name"
|
||||
field.SingleSelectField.Options = []queries.SingleSelectFieldOptions{
|
||||
field.SingleSelectField.Options = []SingleSelectFieldOptions{
|
||||
{
|
||||
ID: "123",
|
||||
Name: "name",
|
||||
|
|
@ -115,35 +120,35 @@ func TestJSONProjectField_SingleSelectType(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
b, err := json.Marshal(JSONProjectField(field))
|
||||
b, err := json.Marshal(field.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","name":"name","type":"ProjectV2SingleSelectField","options":[{"id":"123","name":"name"},{"id":"456","name":"name2"}]}`, string(b))
|
||||
assert.JSONEq(t, `{"id":"123","name":"name","type":"ProjectV2SingleSelectField","options":[{"id":"123","name":"name"},{"id":"456","name":"name2"}]}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectField_ProjectV2IterationField(t *testing.T) {
|
||||
field := queries.ProjectField{}
|
||||
field := ProjectField{}
|
||||
field.TypeName = "ProjectV2IterationField"
|
||||
field.IterationField.ID = "123"
|
||||
field.IterationField.Name = "name"
|
||||
|
||||
b, err := json.Marshal(JSONProjectField(field))
|
||||
b, err := json.Marshal(field.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","name":"name","type":"ProjectV2IterationField"}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectFields(t *testing.T) {
|
||||
field := queries.ProjectField{}
|
||||
field := ProjectField{}
|
||||
field.TypeName = "ProjectV2Field"
|
||||
field.Field.ID = "123"
|
||||
field.Field.Name = "name"
|
||||
|
||||
field2 := queries.ProjectField{}
|
||||
field2 := ProjectField{}
|
||||
field2.TypeName = "ProjectV2SingleSelectField"
|
||||
field2.SingleSelectField.ID = "123"
|
||||
field2.SingleSelectField.Name = "name"
|
||||
field2.SingleSelectField.Options = []queries.SingleSelectFieldOptions{
|
||||
field2.SingleSelectField.Options = []SingleSelectFieldOptions{
|
||||
{
|
||||
ID: "123",
|
||||
Name: "name",
|
||||
|
|
@ -154,73 +159,72 @@ func TestJSONProjectFields(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
p := &queries.Project{
|
||||
p := &Project{
|
||||
Fields: struct {
|
||||
TotalCount int
|
||||
Nodes []queries.ProjectField
|
||||
PageInfo queries.PageInfo
|
||||
Nodes []ProjectField
|
||||
PageInfo PageInfo
|
||||
}{
|
||||
Nodes: []queries.ProjectField{field, field2},
|
||||
Nodes: []ProjectField{field, field2},
|
||||
TotalCount: 5,
|
||||
},
|
||||
}
|
||||
projectFieldsJSON := JSONProjectFields(p)
|
||||
b, err := json.Marshal(projectFieldsJSON)
|
||||
b, err := json.Marshal(p.Fields.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"fields":[{"id":"123","name":"name","type":"ProjectV2Field"},{"id":"123","name":"name","type":"ProjectV2SingleSelectField","options":[{"id":"123","name":"name"},{"id":"456","name":"name2"}]}],"totalCount":5}`, string(b))
|
||||
assert.JSONEq(t, `{"fields":[{"id":"123","name":"name","type":"ProjectV2Field"},{"id":"123","name":"name","type":"ProjectV2SingleSelectField","options":[{"id":"123","name":"name"},{"id":"456","name":"name2"}]}],"totalCount":5}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectItem_DraftIssue(t *testing.T) {
|
||||
item := queries.ProjectItem{}
|
||||
item := ProjectItem{}
|
||||
item.Content.TypeName = "DraftIssue"
|
||||
item.Id = "123"
|
||||
item.Content.DraftIssue.Title = "title"
|
||||
item.Content.DraftIssue.Body = "a body"
|
||||
|
||||
b, err := json.Marshal(JSONProjectItem(item))
|
||||
b, err := json.Marshal(item.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","title":"title","body":"a body","type":"DraftIssue"}`, string(b))
|
||||
assert.JSONEq(t, `{"id":"123","title":"title","body":"a body","type":"DraftIssue"}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectItem_Issue(t *testing.T) {
|
||||
item := queries.ProjectItem{}
|
||||
item := ProjectItem{}
|
||||
item.Content.TypeName = "Issue"
|
||||
item.Id = "123"
|
||||
item.Content.Issue.Title = "title"
|
||||
item.Content.Issue.Body = "a body"
|
||||
item.Content.Issue.URL = "a-url"
|
||||
|
||||
b, err := json.Marshal(JSONProjectItem(item))
|
||||
b, err := json.Marshal(item.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","title":"title","body":"a body","type":"Issue","url":"a-url"}`, string(b))
|
||||
assert.JSONEq(t, `{"id":"123","title":"title","body":"a body","type":"Issue","url":"a-url"}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectItem_PullRequest(t *testing.T) {
|
||||
item := queries.ProjectItem{}
|
||||
item := ProjectItem{}
|
||||
item.Content.TypeName = "PullRequest"
|
||||
item.Id = "123"
|
||||
item.Content.PullRequest.Title = "title"
|
||||
item.Content.PullRequest.Body = "a body"
|
||||
item.Content.PullRequest.URL = "a-url"
|
||||
|
||||
b, err := json.Marshal(JSONProjectItem(item))
|
||||
b, err := json.Marshal(item.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","title":"title","body":"a body","type":"PullRequest","url":"a-url"}`, string(b))
|
||||
assert.JSONEq(t, `{"id":"123","title":"title","body":"a body","type":"PullRequest","url":"a-url"}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectDetailedItems(t *testing.T) {
|
||||
p := &queries.Project{}
|
||||
p := &Project{}
|
||||
p.Items.TotalCount = 5
|
||||
p.Items.Nodes = []queries.ProjectItem{
|
||||
p.Items.Nodes = []ProjectItem{
|
||||
{
|
||||
Id: "issueId",
|
||||
Content: queries.ProjectItemContent{
|
||||
Content: ProjectItemContent{
|
||||
TypeName: "Issue",
|
||||
Issue: queries.Issue{
|
||||
Issue: Issue{
|
||||
Title: "Issue title",
|
||||
Body: "a body",
|
||||
Number: 1,
|
||||
|
|
@ -235,9 +239,9 @@ func TestJSONProjectDetailedItems(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Id: "pullRequestId",
|
||||
Content: queries.ProjectItemContent{
|
||||
Content: ProjectItemContent{
|
||||
TypeName: "PullRequest",
|
||||
PullRequest: queries.PullRequest{
|
||||
PullRequest: PullRequest{
|
||||
Title: "Pull Request title",
|
||||
Body: "a body",
|
||||
Number: 2,
|
||||
|
|
@ -252,9 +256,9 @@ func TestJSONProjectDetailedItems(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Id: "draftIssueId",
|
||||
Content: queries.ProjectItemContent{
|
||||
Content: ProjectItemContent{
|
||||
TypeName: "DraftIssue",
|
||||
DraftIssue: queries.DraftIssue{
|
||||
DraftIssue: DraftIssue{
|
||||
Title: "Pull Request title",
|
||||
Body: "a body",
|
||||
},
|
||||
|
|
@ -262,56 +266,56 @@ func TestJSONProjectDetailedItems(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
out, err := json.Marshal(JSONProjectDetailedItems(p))
|
||||
out, err := json.Marshal(p.DetailedItems())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(
|
||||
assert.JSONEq(
|
||||
t,
|
||||
`{"items":[{"content":{"type":"Issue","body":"a body","title":"Issue title","number":1,"repository":"cli/go-gh","url":"issue-url"},"id":"issueId"},{"content":{"type":"PullRequest","body":"a body","title":"Pull Request title","number":2,"repository":"cli/go-gh","url":"pr-url"},"id":"pullRequestId"},{"content":{"type":"DraftIssue","body":"a body","title":"Pull Request title"},"id":"draftIssueId"}],"totalCount":5}`,
|
||||
string(out))
|
||||
}
|
||||
|
||||
func TestJSONProjectDraftIssue(t *testing.T) {
|
||||
item := queries.DraftIssue{}
|
||||
item := DraftIssue{}
|
||||
item.ID = "123"
|
||||
item.Title = "title"
|
||||
item.Body = "a body"
|
||||
|
||||
b, err := json.Marshal(JSONProjectDraftIssue(item))
|
||||
b, err := json.Marshal(item.ExportData(nil))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `{"id":"123","title":"title","body":"a body","type":"DraftIssue"}`, string(b))
|
||||
assert.JSONEq(t, `{"id":"123","title":"title","body":"a body","type":"DraftIssue"}`, string(b))
|
||||
}
|
||||
|
||||
func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldIterationValue(t *testing.T) {
|
||||
iterationField := queries.ProjectField{TypeName: "ProjectV2IterationField"}
|
||||
iterationField := ProjectField{TypeName: "ProjectV2IterationField"}
|
||||
iterationField.IterationField.ID = "sprint"
|
||||
iterationField.IterationField.Name = "Sprint"
|
||||
|
||||
iterationFieldValue := queries.FieldValueNodes{Type: "ProjectV2ItemFieldIterationValue"}
|
||||
iterationFieldValue := FieldValueNodes{Type: "ProjectV2ItemFieldIterationValue"}
|
||||
iterationFieldValue.ProjectV2ItemFieldIterationValue.Title = "Iteration Title"
|
||||
iterationFieldValue.ProjectV2ItemFieldIterationValue.Field = iterationField
|
||||
|
||||
draftIssue := queries.ProjectItem{
|
||||
draftIssue := ProjectItem{
|
||||
Id: "draftIssueId",
|
||||
Content: queries.ProjectItemContent{
|
||||
Content: ProjectItemContent{
|
||||
TypeName: "DraftIssue",
|
||||
DraftIssue: queries.DraftIssue{
|
||||
DraftIssue: DraftIssue{
|
||||
Title: "Pull Request title",
|
||||
Body: "a body",
|
||||
},
|
||||
},
|
||||
}
|
||||
draftIssue.FieldValues.Nodes = []queries.FieldValueNodes{
|
||||
draftIssue.FieldValues.Nodes = []FieldValueNodes{
|
||||
iterationFieldValue,
|
||||
}
|
||||
p := &queries.Project{}
|
||||
p.Fields.Nodes = []queries.ProjectField{iterationField}
|
||||
p := &Project{}
|
||||
p.Fields.Nodes = []ProjectField{iterationField}
|
||||
p.Items.TotalCount = 5
|
||||
p.Items.Nodes = []queries.ProjectItem{
|
||||
p.Items.Nodes = []ProjectItem{
|
||||
draftIssue,
|
||||
}
|
||||
|
||||
out, err := json.Marshal(JSONProjectDetailedItems(p))
|
||||
out, err := json.Marshal(p.DetailedItems())
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(
|
||||
t,
|
||||
|
|
@ -321,35 +325,35 @@ func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldIterationValue(t *testing.
|
|||
}
|
||||
|
||||
func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldMilestoneValue(t *testing.T) {
|
||||
milestoneField := queries.ProjectField{TypeName: "ProjectV2IterationField"}
|
||||
milestoneField := ProjectField{TypeName: "ProjectV2IterationField"}
|
||||
milestoneField.IterationField.ID = "milestone"
|
||||
milestoneField.IterationField.Name = "Milestone"
|
||||
|
||||
milestoneFieldValue := queries.FieldValueNodes{Type: "ProjectV2ItemFieldMilestoneValue"}
|
||||
milestoneFieldValue := FieldValueNodes{Type: "ProjectV2ItemFieldMilestoneValue"}
|
||||
milestoneFieldValue.ProjectV2ItemFieldMilestoneValue.Milestone.Title = "Milestone Title"
|
||||
milestoneFieldValue.ProjectV2ItemFieldMilestoneValue.Field = milestoneField
|
||||
|
||||
draftIssue := queries.ProjectItem{
|
||||
draftIssue := ProjectItem{
|
||||
Id: "draftIssueId",
|
||||
Content: queries.ProjectItemContent{
|
||||
Content: ProjectItemContent{
|
||||
TypeName: "DraftIssue",
|
||||
DraftIssue: queries.DraftIssue{
|
||||
DraftIssue: DraftIssue{
|
||||
Title: "Pull Request title",
|
||||
Body: "a body",
|
||||
},
|
||||
},
|
||||
}
|
||||
draftIssue.FieldValues.Nodes = []queries.FieldValueNodes{
|
||||
draftIssue.FieldValues.Nodes = []FieldValueNodes{
|
||||
milestoneFieldValue,
|
||||
}
|
||||
p := &queries.Project{}
|
||||
p.Fields.Nodes = []queries.ProjectField{milestoneField}
|
||||
p := &Project{}
|
||||
p.Fields.Nodes = []ProjectField{milestoneField}
|
||||
p.Items.TotalCount = 5
|
||||
p.Items.Nodes = []queries.ProjectItem{
|
||||
p.Items.Nodes = []ProjectItem{
|
||||
draftIssue,
|
||||
}
|
||||
|
||||
out, err := json.Marshal(JSONProjectDetailedItems(p))
|
||||
out, err := json.Marshal(p.DetailedItems())
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(
|
||||
t,
|
||||
|
|
@ -357,10 +361,3 @@ func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldMilestoneValue(t *testing.
|
|||
string(out))
|
||||
|
||||
}
|
||||
|
||||
func TestCamelCase(t *testing.T) {
|
||||
assert.Equal(t, "camelCase", camelCase("camelCase"))
|
||||
assert.Equal(t, "camelCase", camelCase("CamelCase"))
|
||||
assert.Equal(t, "c", camelCase("C"))
|
||||
assert.Equal(t, "", camelCase(""))
|
||||
}
|
||||
|
|
@ -128,12 +128,8 @@ type Project struct {
|
|||
TotalCount int
|
||||
Nodes []ProjectItem
|
||||
} `graphql:"items(first: $firstItems, after: $afterItems)"`
|
||||
Fields struct {
|
||||
TotalCount int
|
||||
Nodes []ProjectField
|
||||
PageInfo PageInfo
|
||||
} `graphql:"fields(first: $firstFields, after: $afterFields)"`
|
||||
Owner struct {
|
||||
Fields ProjectFields `graphql:"fields(first: $firstFields, after: $afterFields)"`
|
||||
Owner struct {
|
||||
TypeName string `graphql:"__typename"`
|
||||
User struct {
|
||||
Login string
|
||||
|
|
@ -144,6 +140,36 @@ type Project struct {
|
|||
}
|
||||
}
|
||||
|
||||
func (p Project) DetailedItems() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"items": serializeProjectWithItems(&p),
|
||||
"totalCount": p.Items.TotalCount,
|
||||
}
|
||||
}
|
||||
|
||||
func (p Project) ExportData(_ []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"number": p.Number,
|
||||
"url": p.URL,
|
||||
"shortDescription": p.ShortDescription,
|
||||
"public": p.Public,
|
||||
"closed": p.Closed,
|
||||
"title": p.Title,
|
||||
"id": p.ID,
|
||||
"readme": p.Readme,
|
||||
"items": map[string]interface{}{
|
||||
"totalCount": p.Items.TotalCount,
|
||||
},
|
||||
"fields": map[string]interface{}{
|
||||
"totalCount": p.Fields.TotalCount,
|
||||
},
|
||||
"owner": map[string]interface{}{
|
||||
"type": p.OwnerType(),
|
||||
"login": p.OwnerLogin(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p Project) OwnerType() string {
|
||||
return p.Owner.TypeName
|
||||
}
|
||||
|
|
@ -155,6 +181,22 @@ func (p Project) OwnerLogin() string {
|
|||
return p.Owner.Organization.Login
|
||||
}
|
||||
|
||||
type Projects struct {
|
||||
Nodes []Project
|
||||
TotalCount int
|
||||
}
|
||||
|
||||
func (p Projects) ExportData(_ []string) map[string]interface{} {
|
||||
v := make([]map[string]interface{}, len(p.Nodes))
|
||||
for i := range p.Nodes {
|
||||
v[i] = p.Nodes[i].ExportData(nil)
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"projects": v,
|
||||
"totalCount": p.TotalCount,
|
||||
}
|
||||
}
|
||||
|
||||
// ProjectItem is a ProjectV2Item GraphQL object https://docs.github.com/en/graphql/reference/objects#projectv2item.
|
||||
type ProjectItem struct {
|
||||
Content ProjectItemContent
|
||||
|
|
@ -284,6 +326,19 @@ type DraftIssue struct {
|
|||
Title string
|
||||
}
|
||||
|
||||
func (i DraftIssue) ExportData(_ []string) map[string]interface{} {
|
||||
v := map[string]interface{}{
|
||||
"title": i.Title,
|
||||
"body": i.Body,
|
||||
"type": "DraftIssue",
|
||||
}
|
||||
// Emulate omitempty.
|
||||
if i.ID != "" {
|
||||
v["id"] = i.ID
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
type PullRequest struct {
|
||||
Body string
|
||||
Title string
|
||||
|
|
@ -294,6 +349,17 @@ type PullRequest struct {
|
|||
}
|
||||
}
|
||||
|
||||
func (pr PullRequest) ExportData(_ []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "PullRequest",
|
||||
"body": pr.Body,
|
||||
"title": pr.Title,
|
||||
"number": pr.Number,
|
||||
"repository": pr.Repository.NameWithOwner,
|
||||
"url": pr.URL,
|
||||
}
|
||||
}
|
||||
|
||||
type Issue struct {
|
||||
Body string
|
||||
Title string
|
||||
|
|
@ -304,6 +370,50 @@ type Issue struct {
|
|||
}
|
||||
}
|
||||
|
||||
func (i Issue) ExportData(_ []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "Issue",
|
||||
"body": i.Body,
|
||||
"title": i.Title,
|
||||
"number": i.Number,
|
||||
"repository": i.Repository.NameWithOwner,
|
||||
"url": i.URL,
|
||||
}
|
||||
}
|
||||
|
||||
func (p ProjectItem) DetailedItem() exportable {
|
||||
switch p.Type() {
|
||||
case "DraftIssue":
|
||||
return DraftIssue{
|
||||
Body: p.Body(),
|
||||
Title: p.Title(),
|
||||
}
|
||||
|
||||
case "Issue":
|
||||
return Issue{
|
||||
Body: p.Body(),
|
||||
Title: p.Title(),
|
||||
Number: p.Number(),
|
||||
Repository: struct{ NameWithOwner string }{
|
||||
NameWithOwner: p.Repo(),
|
||||
},
|
||||
URL: p.URL(),
|
||||
}
|
||||
|
||||
case "PullRequest":
|
||||
return PullRequest{
|
||||
Body: p.Body(),
|
||||
Title: p.Title(),
|
||||
Number: p.Number(),
|
||||
Repository: struct{ NameWithOwner string }{
|
||||
NameWithOwner: p.Repo(),
|
||||
},
|
||||
URL: p.URL(),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type is the underlying type of the project item.
|
||||
func (p ProjectItem) Type() string {
|
||||
return p.Content.TypeName
|
||||
|
|
@ -374,6 +484,20 @@ func (p ProjectItem) URL() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (p ProjectItem) ExportData(_ []string) map[string]interface{} {
|
||||
v := map[string]interface{}{
|
||||
"id": p.ID(),
|
||||
"title": p.Title(),
|
||||
"body": p.Body(),
|
||||
"type": p.Type(),
|
||||
}
|
||||
// Emulate omitempty.
|
||||
if url := p.URL(); url != "" {
|
||||
v["url"] = url
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ProjectItems returns the items of a project. If the OwnerType is VIEWER, no login is required.
|
||||
// If limit is 0, the default limit is used.
|
||||
func (c *Client) ProjectItems(o *Owner, number int32, limit int) (*Project, error) {
|
||||
|
|
@ -631,6 +755,13 @@ type SingleSelectFieldOptions struct {
|
|||
Name string
|
||||
}
|
||||
|
||||
func (f SingleSelectFieldOptions) ExportData(_ []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": f.ID,
|
||||
"name": f.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func (p ProjectField) Options() []SingleSelectFieldOptions {
|
||||
if p.TypeName == "ProjectV2SingleSelectField" {
|
||||
var options []SingleSelectFieldOptions
|
||||
|
|
@ -645,6 +776,40 @@ func (p ProjectField) Options() []SingleSelectFieldOptions {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p ProjectField) ExportData(_ []string) map[string]interface{} {
|
||||
v := map[string]interface{}{
|
||||
"id": p.ID(),
|
||||
"name": p.Name(),
|
||||
"type": p.Type(),
|
||||
}
|
||||
// Emulate omitempty
|
||||
if opts := p.Options(); len(opts) != 0 {
|
||||
options := make([]map[string]interface{}, len(opts))
|
||||
for i, opt := range opts {
|
||||
options[i] = opt.ExportData(nil)
|
||||
}
|
||||
v["options"] = options
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
type ProjectFields struct {
|
||||
TotalCount int
|
||||
Nodes []ProjectField
|
||||
PageInfo PageInfo
|
||||
}
|
||||
|
||||
func (p ProjectFields) ExportData(_ []string) map[string]interface{} {
|
||||
fields := make([]map[string]interface{}, len(p.Nodes))
|
||||
for i := range p.Nodes {
|
||||
fields[i] = p.Nodes[i].ExportData(nil)
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"fields": fields,
|
||||
"totalCount": p.TotalCount,
|
||||
}
|
||||
}
|
||||
|
||||
// ProjectFields returns a project with fields. If the OwnerType is VIEWER, no login is required.
|
||||
// If limit is 0, the default limit is used.
|
||||
func (c *Client) ProjectFields(o *Owner, number int32, limit int) (*Project, error) {
|
||||
|
|
@ -1084,17 +1249,17 @@ func (c *Client) NewProject(canPrompt bool, o *Owner, number int32, fields bool)
|
|||
return nil, fmt.Errorf("project number is required when not running interactively")
|
||||
}
|
||||
|
||||
projects, _, err := c.Projects(o.Login, o.Type, 0, fields)
|
||||
projects, err := c.Projects(o.Login, o.Type, 0, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(projects) == 0 {
|
||||
if len(projects.Nodes) == 0 {
|
||||
return nil, fmt.Errorf("no projects found for %s", o.Login)
|
||||
}
|
||||
|
||||
options := make([]string, 0, len(projects))
|
||||
for _, p := range projects {
|
||||
options := make([]string, 0, len(projects.Nodes))
|
||||
for _, p := range projects.Nodes {
|
||||
title := fmt.Sprintf("%s (#%d)", p.Title, p.Number)
|
||||
options = append(options, title)
|
||||
}
|
||||
|
|
@ -1104,16 +1269,17 @@ func (c *Client) NewProject(canPrompt bool, o *Owner, number int32, fields bool)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &projects[answerIndex], nil
|
||||
return &projects.Nodes[answerIndex], nil
|
||||
}
|
||||
|
||||
// Projects returns all the projects for an Owner. If the OwnerType is VIEWER, no login is required.
|
||||
// If limit is 0, the default limit is used.
|
||||
func (c *Client) Projects(login string, t OwnerType, limit int, fields bool) ([]Project, int, error) {
|
||||
projects := make([]Project, 0)
|
||||
func (c *Client) Projects(login string, t OwnerType, limit int, fields bool) (Projects, error) {
|
||||
projects := Projects{
|
||||
Nodes: make([]Project, 0),
|
||||
}
|
||||
cursor := (*githubv4.String)(nil)
|
||||
hasNextPage := false
|
||||
totalCount := 0
|
||||
|
||||
if limit == 0 {
|
||||
limit = LimitDefault
|
||||
|
|
@ -1149,38 +1315,38 @@ func (c *Client) Projects(login string, t OwnerType, limit int, fields bool) ([]
|
|||
if t == UserOwner {
|
||||
var query userProjects
|
||||
if err := c.doQuery("UserProjects", &query, variables); err != nil {
|
||||
return projects, 0, err
|
||||
return projects, err
|
||||
}
|
||||
projects = append(projects, query.Owner.Projects.Nodes...)
|
||||
projects.Nodes = append(projects.Nodes, query.Owner.Projects.Nodes...)
|
||||
hasNextPage = query.Owner.Projects.PageInfo.HasNextPage
|
||||
cursor = &query.Owner.Projects.PageInfo.EndCursor
|
||||
totalCount = query.Owner.Projects.TotalCount
|
||||
projects.TotalCount = query.Owner.Projects.TotalCount
|
||||
} else if t == OrgOwner {
|
||||
var query orgProjects
|
||||
if err := c.doQuery("OrgProjects", &query, variables); err != nil {
|
||||
return projects, 0, err
|
||||
return projects, err
|
||||
}
|
||||
projects = append(projects, query.Owner.Projects.Nodes...)
|
||||
projects.Nodes = append(projects.Nodes, query.Owner.Projects.Nodes...)
|
||||
hasNextPage = query.Owner.Projects.PageInfo.HasNextPage
|
||||
cursor = &query.Owner.Projects.PageInfo.EndCursor
|
||||
totalCount = query.Owner.Projects.TotalCount
|
||||
projects.TotalCount = query.Owner.Projects.TotalCount
|
||||
} else if t == ViewerOwner {
|
||||
var query viewerProjects
|
||||
if err := c.doQuery("ViewerProjects", &query, variables); err != nil {
|
||||
return projects, 0, err
|
||||
return projects, err
|
||||
}
|
||||
projects = append(projects, query.Owner.Projects.Nodes...)
|
||||
projects.Nodes = append(projects.Nodes, query.Owner.Projects.Nodes...)
|
||||
hasNextPage = query.Owner.Projects.PageInfo.HasNextPage
|
||||
cursor = &query.Owner.Projects.PageInfo.EndCursor
|
||||
totalCount = query.Owner.Projects.TotalCount
|
||||
projects.TotalCount = query.Owner.Projects.TotalCount
|
||||
}
|
||||
|
||||
if !hasNextPage || len(projects) >= limit {
|
||||
return projects, totalCount, nil
|
||||
if !hasNextPage || len(projects.Nodes) >= limit {
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
if len(projects)+LimitMax > limit {
|
||||
first := limit - len(projects)
|
||||
if len(projects.Nodes)+LimitMax > limit {
|
||||
first := limit - len(projects.Nodes)
|
||||
variables["first"] = githubv4.Int(first)
|
||||
}
|
||||
variables["after"] = cursor
|
||||
|
|
@ -1223,3 +1389,107 @@ func requiredScopesFromServerMessage(msg string) []string {
|
|||
}
|
||||
return scopes
|
||||
}
|
||||
|
||||
func projectFieldValueData(v FieldValueNodes) interface{} {
|
||||
switch v.Type {
|
||||
case "ProjectV2ItemFieldDateValue":
|
||||
return v.ProjectV2ItemFieldDateValue.Date
|
||||
case "ProjectV2ItemFieldIterationValue":
|
||||
return map[string]interface{}{
|
||||
"title": v.ProjectV2ItemFieldIterationValue.Title,
|
||||
"startDate": v.ProjectV2ItemFieldIterationValue.StartDate,
|
||||
"duration": v.ProjectV2ItemFieldIterationValue.Duration,
|
||||
}
|
||||
case "ProjectV2ItemFieldNumberValue":
|
||||
return v.ProjectV2ItemFieldNumberValue.Number
|
||||
case "ProjectV2ItemFieldSingleSelectValue":
|
||||
return v.ProjectV2ItemFieldSingleSelectValue.Name
|
||||
case "ProjectV2ItemFieldTextValue":
|
||||
return v.ProjectV2ItemFieldTextValue.Text
|
||||
case "ProjectV2ItemFieldMilestoneValue":
|
||||
return map[string]interface{}{
|
||||
"title": v.ProjectV2ItemFieldMilestoneValue.Milestone.Title,
|
||||
"description": v.ProjectV2ItemFieldMilestoneValue.Milestone.Description,
|
||||
"dueOn": v.ProjectV2ItemFieldMilestoneValue.Milestone.DueOn,
|
||||
}
|
||||
case "ProjectV2ItemFieldLabelValue":
|
||||
names := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldLabelValue.Labels.Nodes {
|
||||
names = append(names, p.Name)
|
||||
}
|
||||
return names
|
||||
case "ProjectV2ItemFieldPullRequestValue":
|
||||
urls := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldPullRequestValue.PullRequests.Nodes {
|
||||
urls = append(urls, p.Url)
|
||||
}
|
||||
return urls
|
||||
case "ProjectV2ItemFieldRepositoryValue":
|
||||
return v.ProjectV2ItemFieldRepositoryValue.Repository.Url
|
||||
case "ProjectV2ItemFieldUserValue":
|
||||
logins := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldUserValue.Users.Nodes {
|
||||
logins = append(logins, p.Login)
|
||||
}
|
||||
return logins
|
||||
case "ProjectV2ItemFieldReviewerValue":
|
||||
names := make([]string, 0)
|
||||
for _, p := range v.ProjectV2ItemFieldReviewerValue.Reviewers.Nodes {
|
||||
if p.Type == "Team" {
|
||||
names = append(names, p.Team.Name)
|
||||
} else if p.Type == "User" {
|
||||
names = append(names, p.User.Login)
|
||||
}
|
||||
}
|
||||
return names
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// serialize creates a map from field to field values
|
||||
func serializeProjectWithItems(project *Project) []map[string]interface{} {
|
||||
fields := make(map[string]string)
|
||||
|
||||
// make a map of fields by ID
|
||||
for _, f := range project.Fields.Nodes {
|
||||
fields[f.ID()] = camelCase(f.Name())
|
||||
}
|
||||
itemsSlice := make([]map[string]interface{}, 0)
|
||||
|
||||
// for each value, look up the name by ID
|
||||
// and set the value to the field value
|
||||
for _, i := range project.Items.Nodes {
|
||||
o := make(map[string]interface{})
|
||||
o["id"] = i.Id
|
||||
if projectItem := i.DetailedItem(); projectItem != nil {
|
||||
o["content"] = projectItem.ExportData(nil)
|
||||
} else {
|
||||
o["content"] = nil
|
||||
}
|
||||
for _, v := range i.FieldValues.Nodes {
|
||||
id := v.ID()
|
||||
value := projectFieldValueData(v)
|
||||
|
||||
o[fields[id]] = value
|
||||
}
|
||||
itemsSlice = append(itemsSlice, o)
|
||||
}
|
||||
return itemsSlice
|
||||
}
|
||||
|
||||
// camelCase converts a string to camelCase, which is useful for turning Go field names to JSON keys.
|
||||
func camelCase(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(s) == 1 {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
return strings.ToLower(s[0:1]) + s[1:]
|
||||
}
|
||||
|
||||
type exportable interface {
|
||||
ExportData([]string) map[string]interface{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,3 +428,10 @@ func TestProjectItems_FieldTitle(t *testing.T) {
|
|||
assert.Equal(t, project.Items.Nodes[0].FieldValues.Nodes[0].ProjectV2ItemFieldIterationValue.Title, "Iteration Title 1")
|
||||
assert.Equal(t, project.Items.Nodes[0].FieldValues.Nodes[1].ProjectV2ItemFieldMilestoneValue.Milestone.Title, "Milestone Title 1")
|
||||
}
|
||||
|
||||
func TestCamelCase(t *testing.T) {
|
||||
assert.Equal(t, "camelCase", camelCase("camelCase"))
|
||||
assert.Equal(t, "camelCase", camelCase("CamelCase"))
|
||||
assert.Equal(t, "c", camelCase("C"))
|
||||
assert.Equal(t, "", camelCase(""))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"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"
|
||||
|
|
@ -107,7 +106,7 @@ func runView(config viewConfig) error {
|
|||
}
|
||||
|
||||
if config.opts.exporter != nil {
|
||||
return printJSON(config, *project)
|
||||
return config.opts.exporter.Write(config.io, *project)
|
||||
}
|
||||
|
||||
return printResults(config, project)
|
||||
|
|
@ -191,8 +190,3 @@ func printResults(config viewConfig, project *queries.Project) error {
|
|||
_, err = fmt.Fprint(config.io.Out, out)
|
||||
return err
|
||||
}
|
||||
|
||||
func printJSON(config viewConfig, project queries.Project) error {
|
||||
projectJSON := format.JSONProject(project)
|
||||
return config.opts.exporter.Write(config.io, projectJSON)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue