X Tutup
package shared import ( "fmt" "sort" "strings" "time" "github.com/cli/cli/api" "github.com/cli/cli/pkg/iostreams" "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/utils" ) type Comment interface { AuthorLogin() string Association() string Content() string Created() time.Time HiddenReason() string IsEdited() bool IsHidden() bool Link() string Reactions() api.ReactionGroups Status() string } func RawCommentList(comments api.Comments, reviews api.PullRequestReviews) string { sortedComments := sortComments(comments, reviews) var b strings.Builder for _, comment := range sortedComments { fmt.Fprint(&b, formatRawComment(comment)) } return b.String() } func formatRawComment(comment Comment) string { if comment.IsHidden() { return "" } var b strings.Builder fmt.Fprintf(&b, "author:\t%s\n", comment.AuthorLogin()) fmt.Fprintf(&b, "association:\t%s\n", strings.ToLower(comment.Association())) fmt.Fprintf(&b, "edited:\t%t\n", comment.IsEdited()) fmt.Fprintf(&b, "status:\t%s\n", formatRawCommentStatus(comment.Status())) fmt.Fprintln(&b, "--") fmt.Fprintln(&b, comment.Content()) fmt.Fprintln(&b, "--") return b.String() } func CommentList(io *iostreams.IOStreams, comments api.Comments, reviews api.PullRequestReviews, preview bool) (string, error) { sortedComments := sortComments(comments, reviews) if preview && len(sortedComments) > 0 { sortedComments = sortedComments[len(sortedComments)-1:] } var b strings.Builder cs := io.ColorScheme() totalCount := comments.TotalCount + reviews.TotalCount retrievedCount := len(sortedComments) hiddenCount := totalCount - retrievedCount if preview && hiddenCount > 0 { fmt.Fprint(&b, cs.Gray(fmt.Sprintf("———————— Not showing %s ————————", utils.Pluralize(hiddenCount, "comment")))) fmt.Fprintf(&b, "\n\n\n") } for i, comment := range sortedComments { last := i+1 == retrievedCount cmt, err := formatComment(io, comment, last) if err != nil { return "", err } fmt.Fprint(&b, cmt) if last { fmt.Fprintln(&b) } } if preview && hiddenCount > 0 { fmt.Fprint(&b, cs.Gray("Use --comments to view the full conversation")) fmt.Fprintln(&b) } return b.String(), nil } func formatComment(io *iostreams.IOStreams, comment Comment, newest bool) (string, error) { var b strings.Builder cs := io.ColorScheme() if comment.IsHidden() { return cs.Bold(formatHiddenComment(comment)), nil } // Header fmt.Fprint(&b, cs.Bold(comment.AuthorLogin())) if comment.Status() != "" { fmt.Fprint(&b, formatCommentStatus(cs, comment.Status())) } if comment.Association() != "NONE" { fmt.Fprint(&b, cs.Boldf(" (%s)", strings.Title(strings.ToLower(comment.Association())))) } fmt.Fprint(&b, cs.Boldf(" • %s", utils.FuzzyAgoAbbr(time.Now(), comment.Created()))) if comment.IsEdited() { fmt.Fprint(&b, cs.Bold(" • Edited")) } if newest { fmt.Fprint(&b, cs.Bold(" • ")) fmt.Fprint(&b, cs.CyanBold("Newest comment")) } fmt.Fprintln(&b) // Reactions if reactions := ReactionGroupList(comment.Reactions()); reactions != "" { fmt.Fprint(&b, reactions) fmt.Fprintln(&b) } // Body var md string var err error if comment.Content() == "" { md = fmt.Sprintf("\n %s\n\n", cs.Gray("No body provided")) } else { style := markdown.GetStyle(io.TerminalTheme()) md, err = markdown.Render(comment.Content(), style, "") if err != nil { return "", err } } fmt.Fprint(&b, md) // Footer if comment.Link() != "" { fmt.Fprintf(&b, cs.Gray("View the full review: %s\n\n"), comment.Link()) } return b.String(), nil } func sortComments(cs api.Comments, rs api.PullRequestReviews) []Comment { comments := cs.Nodes reviews := rs.Nodes var sorted []Comment = make([]Comment, len(comments)+len(reviews)) var i int for _, c := range comments { sorted[i] = c i++ } for _, r := range reviews { sorted[i] = r i++ } sort.Slice(sorted, func(i, j int) bool { return sorted[i].Created().Before(sorted[j].Created()) }) return sorted } const ( approvedStatus = "APPROVED" changesRequestedStatus = "CHANGES_REQUESTED" commentedStatus = "COMMENTED" dismissedStatus = "DISMISSED" ) func formatCommentStatus(cs *iostreams.ColorScheme, status string) string { switch status { case approvedStatus: return fmt.Sprintf(" %s", cs.Green("approved")) case changesRequestedStatus: return fmt.Sprintf(" %s", cs.Red("requested changes")) case commentedStatus, dismissedStatus: return fmt.Sprintf(" %s", strings.ToLower(status)) } return "" } func formatRawCommentStatus(status string) string { if status == approvedStatus || status == changesRequestedStatus || status == commentedStatus || status == dismissedStatus { return strings.ReplaceAll(strings.ToLower(status), "_", " ") } return "none" } func formatHiddenComment(comment Comment) string { var b strings.Builder fmt.Fprint(&b, comment.AuthorLogin()) if comment.Association() != "NONE" { fmt.Fprintf(&b, " (%s)", strings.Title(strings.ToLower(comment.Association()))) } fmt.Fprintf(&b, " • This comment has been marked as %s\n\n", comment.HiddenReason()) return b.String() }
X Tutup