// WriteNewReports takes a list of CI reports read from GitHub, and writes to the repo any that are new.
//
// The passed in logChan variable is used as our intermediary for logging, and allows us to
// use the same logic for logging messages in either our CLI or our App Engine apps, even though
// the two have different logging frameworks.
func WriteNewReports(reportsMap map[string][]ci.Report, repo repository.Repo, logChan chan<- string) error {
	for commit, commitReports := range reportsMap {
		existingReports := ci.ParseAllValid(repo.GetNotes(ci.Ref, commit))
		for _, report := range commitReports {
			bytes, err := json.Marshal(report)
			note := repository.Note(bytes)
			if err != nil {
				return err
			}
			missing := true
			for _, existing := range existingReports {
				if existing == report {
					missing = false
				}
			}
			if missing {
				logChan <- fmt.Sprintf("Found a new report for %.12s: %q", commit, string(bytes))
				if err := repo.AppendNote(ci.Ref, commit, note); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
// WriteNewReviews takes a list of reviews read from GitHub, and writes to the repo any review
// data that has not already been written to it.
//
// The passed in logChan variable is used as our intermediary for logging, and allows us to
// use the same logic for logging messages in either our CLI or our App Engine apps, even though
// the two have different logging frameworks.
func WriteNewReviews(reviews []review.Review, repo repository.Repo, logChan chan<- string) error {
	existingReviews := review.ListAll(repo)
	for _, r := range reviews {
		requestNote, err := r.Request.Write()
		if err != nil {
			return err
		}
		if err != nil {
			return err
		}
		alreadyPresent := false
		if existing := findMatchingExistingReview(r, existingReviews); existing != nil {
			alreadyPresent = RequestsOverlap(existing.Request, r.Request)
			r.Revision = existing.Revision
		}
		if !alreadyPresent {
			requestJSON, err := r.GetJSON()
			if err != nil {
				return err
			}
			logChan <- fmt.Sprintf("Found a new review for %.12s:\n%s\n", r.Revision, requestJSON)
			if err := repo.AppendNote(request.Ref, r.Revision, requestNote); err != nil {
				return err
			}
		}
		if err := WriteNewComments(r, repo, logChan); err != nil {
			return err
		}
	}
	return nil
}
// WriteNewComments takes a list of review comments read from GitHub, and writes to the repo any that are new.
//
// The passed in logChan variable is used as our intermediary for logging, and allows us to
// use the same logic for logging messages in either our CLI or our App Engine apps, even though
// the two have different logging frameworks.
func WriteNewComments(r review.Review, repo repository.Repo, logChan chan<- string) error {
	existingComments := comment.ParseAllValid(repo.GetNotes(comment.Ref, r.Revision))
	for _, commentThread := range r.Comments {
		commentNote, err := commentThread.Comment.Write()
		if err != nil {
			return err
		}
		missing := true
		for _, existing := range existingComments {
			if CommentsOverlap(existing, commentThread.Comment) {
				missing = false
			}
		}
		if missing {
			logChan <- fmt.Sprintf("Found a new comment: %q", string(commentNote))
			if err := repo.AppendNote(comment.Ref, r.Revision, commentNote); err != nil {
				return err
			}
		}
	}
	return nil
}
Exemple #4
0
// Create a new code review request.
//
// The "args" parameter is all of the command line arguments that followed the subcommand.
func requestReview(repo repository.Repo, args []string) error {
	requestFlagSet.Parse(args)

	if !*requestAllowUncommitted {
		// Requesting a code review with uncommited local changes is usually a mistake, so
		// we want to report that to the user instead of creating the request.
		if repo.HasUncommittedChanges() {
			return errors.New("You have uncommitted or untracked files. Use --allow-uncommitted to ignore those.")
		}
	}

	r := buildRequestFromFlags(repo.GetUserEmail())
	if r.ReviewRef == "HEAD" {
		r.ReviewRef = repo.GetHeadRef()
	}
	repo.VerifyGitRefOrDie(r.TargetRef)
	repo.VerifyGitRefOrDie(r.ReviewRef)
	r.BaseCommit = repo.GetCommitHash(r.TargetRef)

	reviewCommits := repo.ListCommitsBetween(r.TargetRef, r.ReviewRef)
	if reviewCommits == nil {
		return errors.New("There are no commits included in the review request")
	}

	if r.Description == "" {
		r.Description = repo.GetCommitMessage(reviewCommits[0])
	}

	note, err := r.Write()
	if err != nil {
		return err
	}
	repo.AppendNote(request.Ref, reviewCommits[0], note)
	if !*requestQuiet {
		fmt.Printf(requestSummaryTemplate, reviewCommits[0], r.TargetRef, r.ReviewRef, r.Description)
	}
	return nil
}
Exemple #5
0
// Create a new code review request.
//
// The "args" parameter is all of the command line arguments that followed the subcommand.
func requestReview(repo repository.Repo, args []string) error {
	requestFlagSet.Parse(args)
	args = requestFlagSet.Args()

	if !*requestAllowUncommitted {
		// Requesting a code review with uncommited local changes is usually a mistake, so
		// we want to report that to the user instead of creating the request.
		hasUncommitted, err := repo.HasUncommittedChanges()
		if err != nil {
			return err
		}
		if hasUncommitted {
			return errors.New("You have uncommitted or untracked files. Use --allow-uncommitted to ignore those.")
		}
	}

	userEmail, err := repo.GetUserEmail()
	if err != nil {
		return err
	}
	r, err := buildRequestFromFlags(userEmail)
	if err != nil {
		return err
	}
	if r.ReviewRef == "HEAD" {
		headRef, err := repo.GetHeadRef()
		if err != nil {
			return err
		}
		r.ReviewRef = headRef
	}
	if err := repo.VerifyGitRef(r.TargetRef); err != nil {
		return err
	}
	if err := repo.VerifyGitRef(r.ReviewRef); err != nil {
		return err
	}

	reviewCommit, baseCommit, err := getReviewCommit(repo, r, args)
	if err != nil {
		return err
	}
	r.BaseCommit = baseCommit
	if r.Description == "" {
		description, err := repo.GetCommitMessage(reviewCommit)
		if err != nil {
			return err
		}
		r.Description = description
	}

	note, err := r.Write()
	if err != nil {
		return err
	}
	repo.AppendNote(request.Ref, reviewCommit, note)
	if !*requestQuiet {
		fmt.Printf(requestSummaryTemplate, reviewCommit, r.TargetRef, r.ReviewRef, r.Description)
	}
	return nil
}
func mirrorRepoToReview(repo repository.Repo, tool review_utils.Tool, syncToRemote bool) {
	if syncToRemote {
		repo.PullNotes("origin", "refs/notes/devtools/*")
	}

	stateHash, err := repo.GetRepoStateHash()
	if err != nil {
		log.Fatal(err)
	}
	if processedStates[repo.GetPath()] != stateHash {
		log.Print("Mirroring repo: ", repo)
		for _, r := range review.ListAll(repo) {
			reviewJson, err := r.GetJSON()
			if err != nil {
				log.Fatal(err)
			}
			log.Println("Mirroring review: ", reviewJson)
			existingComments[r.Revision] = r.Comments
			reviewDetails, err := r.Details()
			if err == nil {
				tool.EnsureRequestExists(repo, *reviewDetails)
			}
		}
		openReviews[repo.GetPath()] = tool.ListOpenReviews(repo)
		processedStates[repo.GetPath()] = stateHash
		tool.Refresh(repo)
	}
ReviewLoop:
	for _, phabricatorReview := range openReviews[repo.GetPath()] {
		if reviewCommit := phabricatorReview.GetFirstCommit(repo); reviewCommit != "" {
			log.Println("Processing review: ", reviewCommit)
			r, err := review.GetSummary(repo, reviewCommit)
			if err != nil {
				log.Fatal(err)
			} else if r == nil {
				log.Printf("Skipping unknown review %q", reviewCommit)
				continue ReviewLoop
			}
			revisionComments := existingComments[reviewCommit]
			log.Printf("Loaded %d comments for %v\n", len(revisionComments), reviewCommit)
			for _, c := range phabricatorReview.LoadComments() {
				if !hasOverlap(c, revisionComments) {
					// The comment is new.
					note, err := c.Write()
					if err != nil {
						log.Fatal(err)
					}
					log.Printf("Appending a comment: %s", string(note))
					repo.AppendNote(comment.Ref, reviewCommit, note)
				} else {
					log.Printf("Skipping '%v', as it has already been written\n", c)
				}
			}
		}
	}
	if syncToRemote {
		if err := repo.PushNotes("origin", "refs/notes/devtools/*"); err != nil {
			log.Printf("Failed to push updates to the repo %v: %v\n", repo, err)
		}
	}
}