From 99e49991bb31cdaa980a45465a42254d53b3edf5 Mon Sep 17 00:00:00 2001 From: Norwin Date: Wed, 14 Sep 2022 03:08:18 +0800 Subject: [PATCH] Add `--fields` to notification & milestone listings (#422) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Together with #415 this finally adds the field flag to all entity listings. closes #342 ### ⚠️ breaking changes ⚠️ This changes the column names of `tea milestones ls`: ```diff - TITLE | OPEN/CLOSED ISSUES | DUEDATE + TITLE | ITEMS | DUEDATE ``` Co-authored-by: Norwin Co-authored-by: 6543 <6543@obermui.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/422 Reviewed-by: delvh Reviewed-by: 6543 <6543@obermui.de> Co-authored-by: Norwin Co-committed-by: Norwin --- cmd/milestones/list.go | 15 +++++- cmd/notifications/list.go | 25 ++++++++-- cmd/notifications/mark_as.go | 6 +-- modules/print/milestone.go | 91 +++++++++++++++++++++------------- modules/print/notification.go | 92 ++++++++++++++++++++--------------- 5 files changed, 149 insertions(+), 80 deletions(-) diff --git a/cmd/milestones/list.go b/cmd/milestones/list.go index e0a8afb..e3faa58 100644 --- a/cmd/milestones/list.go +++ b/cmd/milestones/list.go @@ -13,6 +13,10 @@ import ( "github.com/urfave/cli/v2" ) +var fieldsFlag = flags.FieldsFlag(print.MilestoneFields, []string{ + "title", "items", "duedate", +}) + // CmdMilestonesList represents a sub command of milestones to list milestones var CmdMilestonesList = cli.Command{ Name: "list", @@ -22,6 +26,7 @@ var CmdMilestonesList = cli.Command{ ArgsUsage: " ", // command does not accept arguments Action: RunMilestonesList, Flags: append([]cli.Flag{ + fieldsFlag, &cli.StringFlag{ Name: "state", Usage: "Filter by milestone state (all|open|closed)", @@ -37,10 +42,18 @@ func RunMilestonesList(cmd *cli.Context) error { ctx := context.InitCommand(cmd) ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) + fields, err := fieldsFlag.GetValues(cmd) + if err != nil { + return err + } + state := gitea.StateOpen switch ctx.String("state") { case "all": state = gitea.StateAll + if !cmd.IsSet("fields") { // add to default fields + fields = append(fields, "state") + } case "closed": state = gitea.StateClosed } @@ -55,6 +68,6 @@ func RunMilestonesList(cmd *cli.Context) error { return err } - print.MilestonesList(milestones, ctx.Output, state) + print.MilestonesList(milestones, ctx.Output, fields) return nil } diff --git a/cmd/notifications/list.go b/cmd/notifications/list.go index 054d348..bf76285 100644 --- a/cmd/notifications/list.go +++ b/cmd/notifications/list.go @@ -15,7 +15,11 @@ import ( "github.com/urfave/cli/v2" ) -var notifTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"}, +var notifyFieldsFlag = flags.FieldsFlag(print.NotificationFields, []string{ + "id", "status", "index", "type", "state", "title", +}) + +var notifyTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"}, []string{"issue", "pull", "repository", "commit"}, nil) // CmdNotificationsList represents a sub command of notifications to list notifications @@ -26,7 +30,10 @@ var CmdNotificationsList = cli.Command{ Description: `List notifications`, ArgsUsage: " ", // command does not accept arguments Action: RunNotificationsList, - Flags: append([]cli.Flag{notifTypeFlag}, flags.NotificationFlags...), + Flags: append([]cli.Flag{ + notifyFieldsFlag, + notifyTypeFlag, + }, flags.NotificationFlags...), } // RunNotificationsList list notifications @@ -41,7 +48,7 @@ func RunNotificationsList(ctx *cli.Context) error { } var types []gitea.NotifySubjectType - typesStr, err := notifTypeFlag.GetValues(ctx) + typesStr, err := notifyTypeFlag.GetValues(ctx) if err != nil { return err } @@ -67,7 +74,17 @@ func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects [ listOpts.Page = 1 } + fields, err := notifyFieldsFlag.GetValues(cmd) + if err != nil { + return err + } + if all { + // add repository to the default fields + if !cmd.IsSet("fields") { + fields = append(fields, "repository") + } + news, _, err = client.ListNotifications(gitea.ListNotificationOptions{ ListOptions: listOpts, Status: status, @@ -85,6 +102,6 @@ func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects [ log.Fatal(err) } - print.NotificationsList(news, ctx.Output, all) + print.NotificationsList(news, ctx.Output, fields) return nil } diff --git a/cmd/notifications/mark_as.go b/cmd/notifications/mark_as.go index da8ecc2..3eeebc3 100644 --- a/cmd/notifications/mark_as.go +++ b/cmd/notifications/mark_as.go @@ -28,7 +28,7 @@ var CmdNotificationsMarkRead = cli.Command{ if err != nil { return err } - if !flags.NotificationStateFlag.IsSet() { + if !cmd.IsSet(flags.NotificationStateFlag.Name) { filter = []string{string(gitea.NotifyStatusUnread)} } return markNotificationAs(cmd, filter, gitea.NotifyStatusRead) @@ -49,7 +49,7 @@ var CmdNotificationsMarkUnread = cli.Command{ if err != nil { return err } - if !flags.NotificationStateFlag.IsSet() { + if !cmd.IsSet(flags.NotificationStateFlag.Name) { filter = []string{string(gitea.NotifyStatusRead)} } return markNotificationAs(cmd, filter, gitea.NotifyStatusUnread) @@ -70,7 +70,7 @@ var CmdNotificationsMarkPinned = cli.Command{ if err != nil { return err } - if !flags.NotificationStateFlag.IsSet() { + if !cmd.IsSet(flags.NotificationStateFlag.Name) { filter = []string{string(gitea.NotifyStatusUnread)} } return markNotificationAs(cmd, filter, gitea.NotifyStatusPinned) diff --git a/modules/print/milestone.go b/modules/print/milestone.go index 2997e22..d74c718 100644 --- a/modules/print/milestone.go +++ b/modules/print/milestone.go @@ -24,40 +24,65 @@ func MilestoneDetails(milestone *gitea.Milestone) { } // MilestonesList prints a listing of milestones -func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateType) { - headers := []string{ - "Title", +func MilestonesList(news []*gitea.Milestone, output string, fields []string) { + var printables = make([]printable, len(news)) + for i, x := range news { + printables[i] = &printableMilestone{x} } - if state == gitea.StateAll { - headers = append(headers, "State") - } - headers = append(headers, - "Open/Closed Issues", - "DueDate", - ) - - t := table{headers: headers} - - for _, m := range miles { - var deadline = "" - - if m.Deadline != nil && !m.Deadline.IsZero() { - deadline = FormatTime(*m.Deadline, isMachineReadable(output)) - } - - item := []string{ - m.Title, - } - if state == gitea.StateAll { - item = append(item, string(m.State)) - } - item = append(item, - fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues), - deadline, - ) - t.addRowSlice(item) - } - + t := tableFromItems(fields, printables, isMachineReadable(output)) t.sort(0, true) t.print(output) } + +// MilestoneFields are all available fields to print with MilestonesList +var MilestoneFields = []string{ + "title", + "state", + "items_open", + "items_closed", + "items", + "duedate", + "description", + "created", + "updated", + "closed", + "id", +} + +type printableMilestone struct { + *gitea.Milestone +} + +func (m printableMilestone) FormatField(field string, machineReadable bool) string { + switch field { + case "title": + return m.Title + case "state": + return string(m.State) + case "items_open": + return fmt.Sprintf("%d", m.OpenIssues) + case "items_closed": + return fmt.Sprintf("%d", m.ClosedIssues) + case "items": + return fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues) + case "duedate": + if m.Deadline != nil && !m.Deadline.IsZero() { + return FormatTime(*m.Deadline, machineReadable) + } + case "id": + return fmt.Sprintf("%d", m.ID) + case "description": + return m.Description + case "created": + return FormatTime(m.Created, machineReadable) + case "updated": + if m.Updated != nil { + return FormatTime(*m.Updated, machineReadable) + } + case "closed": + if m.Closed != nil { + return FormatTime(*m.Closed, machineReadable) + } + } + return "" +} diff --git a/modules/print/notification.go b/modules/print/notification.go index 9be86c2..959f776 100644 --- a/modules/print/notification.go +++ b/modules/print/notification.go @@ -12,26 +12,51 @@ import ( ) // NotificationsList prints a listing of notification threads -func NotificationsList(news []*gitea.NotificationThread, output string, showRepository bool) { - headers := []string{ - "ID", - "Status", - "Type", - "State", - "Index", - "Title", - } - if showRepository { - headers = append(headers, "Repository") +func NotificationsList(news []*gitea.NotificationThread, output string, fields []string) { + var printables = make([]printable, len(news)) + for i, x := range news { + printables[i] = &printableNotification{x} } + t := tableFromItems(fields, printables, isMachineReadable(output)) + t.print(output) +} - t := table{headers: headers} +// NotificationFields are all available fields to print with NotificationsList +var NotificationFields = []string{ + "id", + "status", + "updated", - for _, n := range news { - if n.Subject == nil { - continue + // these are about the notification subject + "index", + "type", + "state", + "title", + "repository", +} + +type printableNotification struct { + *gitea.NotificationThread +} + +func (n printableNotification) FormatField(field string, machineReadable bool) string { + switch field { + case "id": + return fmt.Sprintf("%d", n.ID) + + case "status": + status := "read" + if n.Pinned { + status = "pinned" + } else if n.Unread { + status = "unread" } - // if pull or Issue get Index + return status + + case "updated": + return FormatTime(n.UpdatedAt, machineReadable) + + case "index": var index string if n.Subject.Type == "Issue" || n.Subject.Type == "Pull" { index = n.Subject.URL @@ -39,31 +64,20 @@ func NotificationsList(news []*gitea.NotificationThread, output string, showRepo if len(urlParts) != 0 { index = urlParts[len(urlParts)-1] } - index = "#" + index } + return index - status := "read" - if n.Pinned { - status = "pinned" - } else if n.Unread { - status = "unread" - } + case "type": + return string(n.Subject.Type) - item := []string{ - fmt.Sprint(n.ID), - status, - string(n.Subject.Type), - string(n.Subject.State), - index, - n.Subject.Title, - } - if showRepository { - item = append(item, n.Repository.FullName) - } - t.addRowSlice(item) - } - - if t.Len() != 0 { - t.print(output) + case "state": + return string(n.Subject.State) + + case "title": + return n.Subject.Title + + case "repo", "repository": + return n.Repository.FullName } + return "" }