diff options
Diffstat (limited to 'third_party/go/git-appraise/commands/output/output.go')
-rw-r--r-- | third_party/go/git-appraise/commands/output/output.go | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/third_party/go/git-appraise/commands/output/output.go b/third_party/go/git-appraise/commands/output/output.go new file mode 100644 index 000000000000..4613cd38576b --- /dev/null +++ b/third_party/go/git-appraise/commands/output/output.go @@ -0,0 +1,216 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package output contains helper methods for pretty-printing code reviews. +package output + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/google/git-appraise/review" +) + +const ( + // Template for printing the summary of a code review. + reviewSummaryTemplate = `[%s] %.12s + %s +` + // Template for printing the summary of a code review. + reviewDetailsTemplate = ` %q -> %q + reviewers: %q + requester: %q + build status: %s +` + // Template for printing the location of an inline comment + commentLocationTemplate = `%s%q@%.12s +` + // Template for printing a single comment. + commentTemplate = `comment: %s +author: %s +time: %s +status: %s +%s` + // Template for displaying the summary of the comment threads for a review + commentSummaryTemplate = ` comments (%d threads): +` + // Number of lines of context to print for inline comments + contextLineCount = 5 +) + +// getStatusString returns a human friendly string encapsulating both the review's +// resolved status, and its submitted status. +func getStatusString(r *review.Summary) string { + if r.Resolved == nil && r.Submitted { + return "tbr" + } + if r.Resolved == nil { + return "pending" + } + if *r.Resolved && r.Submitted { + return "submitted" + } + if *r.Resolved { + return "accepted" + } + if r.Submitted { + return "danger" + } + if r.Request.TargetRef == "" { + return "abandon" + } + return "rejected" +} + +// PrintSummary prints a single-line summary of a review. +func PrintSummary(r *review.Summary) { + statusString := getStatusString(r) + indentedDescription := strings.Replace(r.Request.Description, "\n", "\n ", -1) + fmt.Printf(reviewSummaryTemplate, statusString, r.Revision, indentedDescription) +} + +// reformatTimestamp takes a timestamp string of the form "0123456789" and changes it +// to the form "Mon Jan _2 13:04:05 UTC 2006". +// +// Timestamps that are not in the format we expect are left alone. +func reformatTimestamp(timestamp string) string { + parsedTimestamp, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + // The timestamp is an unexpected format, so leave it alone + return timestamp + } + t := time.Unix(parsedTimestamp, 0) + return t.Format(time.UnixDate) +} + +// showThread prints the detailed output for an entire comment thread. +func showThread(r *review.Review, thread review.CommentThread) error { + comment := thread.Comment + indent := " " + if comment.Location != nil && comment.Location.Path != "" && comment.Location.Range != nil && comment.Location.Range.StartLine > 0 { + contents, err := r.Repo.Show(comment.Location.Commit, comment.Location.Path) + if err != nil { + return err + } + lines := strings.Split(contents, "\n") + err = comment.Location.Check(r.Repo) + if err != nil { + return err + } + if comment.Location.Range.StartLine <= uint32(len(lines)) { + firstLine := comment.Location.Range.StartLine + lastLine := comment.Location.Range.EndLine + + if firstLine == 0 { + firstLine = 1 + } + + if lastLine == 0 { + lastLine = firstLine + } + + if lastLine == firstLine { + minLine := int(lastLine) - int(contextLineCount) + if minLine <= 0 { + minLine = 1 + } + firstLine = uint32(minLine) + } + + fmt.Printf(commentLocationTemplate, indent, comment.Location.Path, comment.Location.Commit) + fmt.Println(indent + "|" + strings.Join(lines[firstLine-1:lastLine], "\n"+indent+"|")) + } + } + return showSubThread(r, thread, indent) +} + +// showSubThread prints the given comment (sub)thread, indented by the given prefix string. +func showSubThread(r *review.Review, thread review.CommentThread, indent string) error { + statusString := "fyi" + if thread.Resolved != nil { + if *thread.Resolved { + statusString = "lgtm" + } else { + statusString = "needs work" + } + } + comment := thread.Comment + threadHash := thread.Hash + timestamp := reformatTimestamp(comment.Timestamp) + commentSummary := fmt.Sprintf(indent+commentTemplate, threadHash, comment.Author, timestamp, statusString, comment.Description) + indent = indent + " " + indentedSummary := strings.Replace(commentSummary, "\n", "\n"+indent, -1) + fmt.Println(indentedSummary) + for _, child := range thread.Children { + err := showSubThread(r, child, indent) + if err != nil { + return err + } + } + return nil +} + +// printAnalyses prints the static analysis results for the latest commit in the review. +func printAnalyses(r *review.Review) { + fmt.Println(" analyses: ", r.GetAnalysesMessage()) +} + +// printComments prints all of the comments for the review, with snippets of the preceding source code. +func printComments(r *review.Review) error { + fmt.Printf(commentSummaryTemplate, len(r.Comments)) + for _, thread := range r.Comments { + err := showThread(r, thread) + if err != nil { + return err + } + } + return nil +} + +// PrintDetails prints a multi-line overview of a review, including all comments. +func PrintDetails(r *review.Review) error { + PrintSummary(r.Summary) + fmt.Printf(reviewDetailsTemplate, r.Request.ReviewRef, r.Request.TargetRef, + strings.Join(r.Request.Reviewers, ", "), + r.Request.Requester, r.GetBuildStatusMessage()) + printAnalyses(r) + if err := printComments(r); err != nil { + return err + } + return nil +} + +// PrintJSON pretty prints the given review in JSON format. +func PrintJSON(r *review.Review) error { + json, err := r.GetJSON() + if err != nil { + return err + } + fmt.Println(json) + return nil +} + +// PrintDiff prints the diff of the review. +func PrintDiff(r *review.Review, diffArgs ...string) error { + diff, err := r.GetDiff(diffArgs...) + if err != nil { + return err + } + fmt.Println(diff) + return nil +} |