| @@ -602,75 +602,148 @@ func runMRShow(c *Ctx, args []string) int { |
| 602 | 602 | if d.Draft { |
| 603 | 603 | state = "draft" |
| 604 | 604 | } |
| 605 | | fmt.Fprintf(w, "!%d %s [%s] by %s\n%s -> %s @ %.10s\n", d.Number, d.Title, state, d.Author, d.Source, d.TargetRef, d.HeadSHA) |
| 606 | | if len(d.Labels) > 0 { |
| 607 | | fmt.Fprintf(w, "labels: %s\n", strings.Join(d.Labels, ", ")) |
| 608 | | } |
| 609 | | if len(d.ReviewRequests) > 0 { |
| 610 | | fmt.Fprintf(w, "reviewers: %s\n", strings.Join(d.ReviewRequests, ", ")) |
| 611 | | } |
| 605 | v := c.view(w) |
| 606 | v.title(fmt.Sprintf("!%d", d.Number), d.Title, state) |
| 607 | |
| 608 | stackedOn, stacked := "", "" |
| 612 | 609 | if d.StackedOn != nil { |
| 613 | | fmt.Fprintf(w, "stacked on !%d %s\n", d.StackedOn.Number, d.StackedOn.Title) |
| 610 | stackedOn = fmt.Sprintf("!%d %s", d.StackedOn.Number, d.StackedOn.Title) |
| 614 | 611 | } |
| 615 | 612 | for _, k := range d.Stacked { |
| 616 | | fmt.Fprintf(w, "stacked: !%d %s\n", k.Number, k.Title) |
| 613 | if stacked != "" { |
| 614 | stacked += ", " |
| 615 | } |
| 616 | stacked += fmt.Sprintf("!%d %s", k.Number, k.Title) |
| 617 | 617 | } |
| 618 | merged, closed, superseded := "", "", "" |
| 618 | 619 | if d.MergedAt != "" { |
| 619 | | fmt.Fprintf(w, "merged %s%s\n", d.MergedAt, byWhom(d.MergedBy)) |
| 620 | merged = c.when(d.MergedAt) + byWhom(d.MergedBy) |
| 620 | 621 | } |
| 621 | 622 | if d.ClosedAt != "" { |
| 622 | | fmt.Fprintf(w, "closed %s%s\n", d.ClosedAt, byWhom(d.ClosedBy)) |
| 623 | closed = c.when(d.ClosedAt) + byWhom(d.ClosedBy) |
| 623 | 624 | } |
| 624 | 625 | if d.SupersededBy != 0 { |
| 625 | | fmt.Fprintf(w, "superseded by: !%d\n", d.SupersededBy) |
| 626 | | } |
| 627 | | if d.Body != "" { |
| 628 | | fmt.Fprintf(w, "\n%s\n", d.Body) |
| 629 | | } |
| 630 | | for _, cm := range commits { |
| 631 | | fmt.Fprintf(w, "commit: %.10s %s\n", cm.SHA, cm.Subject) |
| 632 | | } |
| 633 | | for _, x := range checks { |
| 634 | | dur := "" |
| 635 | | if x.Duration != "" { |
| 636 | | dur = " in " + x.Duration |
| 637 | | } |
| 638 | | fmt.Fprintf(w, "check: %s %s at %s%s\n", x.Context, x.State, x.UpdatedAt, dur) |
| 639 | | } |
| 640 | | if d.UnresolvedThreads > 0 { |
| 641 | | fmt.Fprintf(w, "unresolved threads: %d\n", d.UnresolvedThreads) |
| 626 | superseded = fmt.Sprintf("!%d", d.SupersededBy) |
| 642 | 627 | } |
| 628 | gates := "" |
| 643 | 629 | if g := d.Gates; g != nil { |
| 644 | 630 | ff := "fast-forward possible" |
| 645 | 631 | if !g.FastForward { |
| 646 | 632 | ff = "fast-forward not possible" |
| 647 | 633 | } |
| 648 | 634 | if len(g.Unmet) == 0 { |
| 649 | | fmt.Fprintf(w, "gates: met; %s\n", ff) |
| 635 | gates = "met; " + ff |
| 650 | 636 | } else { |
| 651 | | fmt.Fprintf(w, "gates: %d unmet; %s\n", len(g.Unmet), ff) |
| 652 | | for _, u := range g.Unmet { |
| 653 | | fmt.Fprintf(w, "gate: %s\n", u) |
| 637 | gates = fmt.Sprintf("%d unmet; %s", len(g.Unmet), ff) |
| 638 | } |
| 639 | } |
| 640 | unresolved := "" |
| 641 | if d.UnresolvedThreads > 0 { |
| 642 | unresolved = fmt.Sprintf("%d", d.UnresolvedThreads) |
| 643 | } |
| 644 | v.fields( |
| 645 | "author", d.Author+", "+c.when(d.CreatedAt), |
| 646 | "source", fmt.Sprintf("%s -> %s", d.Source, d.TargetRef), |
| 647 | "head", fmt.Sprintf("%.10s", d.HeadSHA), |
| 648 | "milestone", d.Milestone, |
| 649 | "labels", strings.Join(d.Labels, ", "), |
| 650 | "reviewers", strings.Join(d.ReviewRequests, ", "), |
| 651 | "stacked on", stackedOn, |
| 652 | "stacked", stacked, |
| 653 | "merged", merged, |
| 654 | "closed", closed, |
| 655 | "superseded by", superseded, |
| 656 | "unresolved threads", unresolved, |
| 657 | "gates", gates, |
| 658 | "url", c.siteURL(repo.Path(), "mrs", strconv.FormatInt(d.Number, 10)), |
| 659 | ) |
| 660 | if g := d.Gates; g != nil && len(g.Unmet) > 0 { |
| 661 | var kv []string |
| 662 | for _, u := range g.Unmet { |
| 663 | kv = append(kv, "unmet", u) |
| 664 | } |
| 665 | v.fields(kv...) |
| 666 | } |
| 667 | v.body(d.Body, d.BodyFormat) |
| 668 | |
| 669 | if len(commits) == 1 { |
| 670 | v.fields("commit", fmt.Sprintf("%.10s %s", commits[0].SHA, commits[0].Subject)) |
| 671 | } else if len(commits) > 1 { |
| 672 | io.WriteString(w, "\n") |
| 673 | tb := c.table(w, "SHA", "SUBJECT") |
| 674 | for _, cm := range commits { |
| 675 | tb.row(cRef(fmt.Sprintf("%.10s", cm.SHA)), cFlex(cm.Subject)) |
| 676 | } |
| 677 | tb.flush() |
| 678 | } |
| 679 | |
| 680 | if len(checks) == 1 { |
| 681 | x := checks[0] |
| 682 | dur := "" |
| 683 | if x.Duration != "" { |
| 684 | dur = " in " + x.Duration |
| 685 | } |
| 686 | v.fields("check", fmt.Sprintf("%s %s at %s%s", x.Context, x.State, c.when(x.UpdatedAt), dur)) |
| 687 | } else if len(checks) > 1 { |
| 688 | io.WriteString(w, "\n") |
| 689 | tb := c.table(w, "CHECK", "STATE", "UPDATED") |
| 690 | for _, x := range checks { |
| 691 | tb.row(cText(x.Context), cState(x.State), cText(c.when(x.UpdatedAt))) |
| 692 | } |
| 693 | tb.flush() |
| 694 | } |
| 695 | |
| 696 | if len(rs) == 1 { |
| 697 | v.fields("review", reviewLine(rs[0])+" at "+c.when(rs[0].CreatedAt)) |
| 698 | } else if len(rs) > 1 { |
| 699 | io.WriteString(w, "\n") |
| 700 | tb := c.table(w, "REVIEWER", "VERDICT", "WHEN") |
| 701 | for _, r := range rs { |
| 702 | verdict := r.Verdict |
| 703 | if r.Stale { |
| 704 | verdict += " (stale)" |
| 705 | } |
| 706 | if !r.Counts { |
| 707 | verdict += " (advisory)" |
| 654 | 708 | } |
| 709 | tb.row(cText(r.Reviewer), cState(verdict), cText(c.when(r.CreatedAt))) |
| 655 | 710 | } |
| 711 | tb.flush() |
| 656 | 712 | } |
| 657 | | for _, r := range rs { |
| 658 | | stale := "" |
| 659 | | if r.Stale { |
| 660 | | stale = " (stale)" |
| 713 | |
| 714 | events := false |
| 715 | for _, cm := range cs { |
| 716 | if cm.Kind != "system" { |
| 717 | continue |
| 661 | 718 | } |
| 662 | | advisory := "" |
| 663 | | if !r.Counts { |
| 664 | | advisory = " (advisory: no write access)" |
| 719 | if !events { |
| 720 | io.WriteString(w, "\n") |
| 721 | events = true |
| 665 | 722 | } |
| 666 | | fmt.Fprintf(w, "review: %s %s%s%s at %s\n", r.Reviewer, r.Verdict, stale, advisory, r.CreatedAt) |
| 723 | v.event(cm.Body, cm.BodyFormat, cm.CreatedAt) |
| 667 | 724 | } |
| 668 | 725 | for _, cm := range cs { |
| 669 | | fmt.Fprintf(w, "\n--- %s at %s\n%s\n", cm.Author, cm.CreatedAt, cm.Body) |
| 726 | if cm.Kind == "system" { |
| 727 | continue |
| 728 | } |
| 729 | v.comment(cm.Author, cm.CreatedAt, cm.Body, cm.BodyFormat) |
| 670 | 730 | } |
| 671 | 731 | }) |
| 672 | 732 | } |
| 673 | 733 | |
| 734 | // reviewLine renders one review as fields prose: "reviewer verdict |
| 735 | // (stale) (advisory) at when". |
| 736 | func reviewLine(r ReviewOut) string { |
| 737 | s := r.Reviewer + " " + r.Verdict |
| 738 | if r.Stale { |
| 739 | s += " (stale)" |
| 740 | } |
| 741 | if !r.Counts { |
| 742 | s += " (advisory: no write access)" |
| 743 | } |
| 744 | return s |
| 745 | } |
| 746 | |
| 674 | 747 | func runMRDiff(c *Ctx, args []string) int { |
| 675 | 748 | repo, mr, code := mrRef(c, args, policy.CanRead) |
| 676 | 749 | if code >= 0 { |