func commentOnReview(repo repository.Repo, args []string) error {
	var r *review.Review
	var err error
	if len(args) > 1 {
		return errors.New("Only commenting on a single review is supported.")
	}
	if len(args) == 1 {
		r, err = review.Get(repo, args[0])
	} else {
		r, err = review.GetCurrent(repo)
	}
	if err != nil {
		return fmt.Errorf("Failed to load the review: %v\n", err)
	}
	if r == nil {
		return errors.New("There is no matching review.")
	}
	if err := validateArgs(repo, args, r.Comments); err != nil {
		return err
	}
	commentedUponCommit, err := r.GetHeadCommit()
	if err != nil {
		return err
	}
	c, err := buildCommentFromFlags(r.Repo, commentedUponCommit)
	if err != nil {
		return err
	}
	return r.AddComment(*c)
}
commentOnReview adds a comment to the current code review.
package commands
import (
	"errors"
	"flag"
	"fmt"
	"github.com/google/git-appraise/commands/input"
	"github.com/google/git-appraise/repository"
	"github.com/google/git-appraise/review"
	"github.com/google/git-appraise/review/comment"
	"github.com/google/git-appraise/review/gpg"
)
var commentFlagSet = flag.NewFlagSet("comment", flag.ExitOnError)
var commentLocation = comment.Range{}
var (
	commentMessageFile = commentFlagSet.String("F", "", "Take the comment from the given file. Use - to read the message from the standard input")
	commentMessage     = commentFlagSet.String("m", "", "Message body of the comment")
	commentParent      = commentFlagSet.String("p", "", "Parent comment")
	commentFile        = commentFlagSet.String("f", "", "File being commented upon")
	commentDetached    = commentFlagSet.Bool("d", false, "Do not attach the comment to a review")
	commentLgtm        = commentFlagSet.Bool("lgtm", false, "'Looks Good To Me'. Set this to express your approval. This cannot be combined with nmw")
	commentNmw         = commentFlagSet.Bool("nmw", false, "'Needs More Work'. Set this to express your disapproval. This cannot be combined with lgtm")
	commentSign        = commentFlagSet.Bool("S", false, "Sign the contents of the comment")
)
func init() {
	commentFlagSet.Var(&commentLocation, "l",
		`File location to be commented upon; requires that the -f flag also be set.
Location follows the following format:
    <START LINE>[+<START COLUMN>][:<END LINE>[+<END COLUMN>]]
So, in order to comment starting on the 5th character of the 2nd line until (and
including) the 4th character of the 7th line, use:
    -l 2+5:7+4`)
}
func commentHashExists(hashToFind string, threads []review.CommentThread) bool {
	for _, thread := range threads {
		if thread.Hash == hashToFind {
			return true
		}
		if commentHashExists(hashToFind, thread.Children) {
			return true
		}
	}
	return false
}
func validateArgs(repo repository.Repo, args []string, threads []review.CommentThread) error {
	if *commentLgtm && *commentNmw {
		return errors.New("You cannot combine the flags -lgtm and -nmw.")
	}
	if commentLocation != (comment.Range{}) && *commentFile == "" {
		return errors.New("Specifying a line number with the -l flag requires that you also specify a file name with the -f flag.")
	}
	if *commentParent != "" && !commentHashExists(*commentParent, threads) {
		return errors.New("There is no matching parent comment.")
	}
	if *commentMessageFile != "" && *commentMessage == "" {
		var err error
		*commentMessage, err = input.FromFile(*commentMessageFile)
		if err != nil {
			return err
		}
	}
	if *commentMessageFile == "" && *commentMessage == "" {
		var err error
		*commentMessage, err = input.LaunchEditor(repo, commentFilename)
		if err != nil {
			return err
		}
	}
	return nil
}
func buildCommentFromFlags(repo repository.Repo, commentedUponCommit string) (*comment.Comment, error) {
	location := comment.Location{
		Commit: commentedUponCommit,
	}
	if *commentFile != "" {
		location.Path = *commentFile
		location.Range = &commentLocation
		if err := location.Check(repo); err != nil {
			return nil, fmt.Errorf("Unable to comment on the given location: %v", err)
		}
	}
	userEmail, err := repo.GetUserEmail()
	if err != nil {
		return nil, err
	}
	c := comment.New(userEmail, *commentMessage)
	c.Location = &location
	c.Parent = *commentParent
	if *commentLgtm || *commentNmw {
		resolved := *commentLgtm
		c.Resolved = &resolved
	}
	if *commentSign {
		key, err := repo.GetUserSigningKey()
		if err != nil {
			return nil, err
		}
		err = gpg.Sign(key, &c)
		if err != nil {
			return nil, err
		}
	}
	return &c, nil
}