// Refresh advises the review tool that the code being reviewed has changed, and to reload it.
//
// This corresponds to calling the diffusion.looksoon API.
func (arc Arcanist) Refresh(repo repository.Repo) {
	// We cannot determine the repo's callsign (the identifier Phabricator uses for the repo)
	// in all cases, but we can figure it out in the case that the mirror runs on the same
	// directories that Phabricator is using. In that scenario, the repo directories default
	// to being named "/var/repo/<CALLSIGN>", so if the repo path starts with that prefix then
	// we can try to strip out that prefix and use the rest as a callsign.
	if strings.HasPrefix(repo.GetPath(), defaultRepoDirPrefix) {
		possibleCallsign := strings.TrimPrefix(repo.GetPath(), defaultRepoDirPrefix)
		request := lookSoonRequest{Callsigns: []string{possibleCallsign}}
		response := make(map[string]interface{})
		runArcCommandOrDie("diffusion.looksoon", request, &response)
	}
}
func mirrorRepoToReview(repo repository.Repo, tool review.Tool, syncToRemote bool) {
	if syncToRemote {
		if err := repo.PullUpdates(); err != nil {
			log.Printf("Failed to pull updates for the repo %v: %v\n", repo, err)
			return
		}
	}

	stateHash := repo.GetRepoStateHash()
	if processedStates[repo.GetPath()] != stateHash {
		log.Print("Mirroring repo: ", repo)
		for _, revision := range repo.ListNotedRevisions(request.Ref) {
			existingComments[revision] = comment.ParseAllValid(repo.GetNotes(comment.Ref, revision))
			for _, req := range request.ParseAllValid(repo.GetNotes(request.Ref, revision)) {
				tool.EnsureRequestExists(repo, revision, req, existingComments[revision])
			}
		}
		openReviews[repo.GetPath()] = tool.ListOpenReviews(repo)
		processedStates[repo.GetPath()] = stateHash
		tool.Refresh(repo)
	}
	for _, review := range openReviews[repo.GetPath()] {
		if reviewCommit := review.GetFirstCommit(repo); reviewCommit != nil {
			log.Println("Processing review: ", *reviewCommit)
			revisionComments := getExistingComments(*reviewCommit)
			log.Printf("Loaded %d comments for %v\n", len(revisionComments), *reviewCommit)
			for _, c := range review.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, c.Author)
				} else {
					log.Printf("Skipping '%v', as it has already been written\n", c)
				}
			}
		}
	}
	if syncToRemote {
		if err := repo.PushUpdates(); err != nil {
			log.Printf("Failed to push updates to the repo %v: %v\n", repo, err)
		}
	}
}
Esempio n. 3
0
// createDifferentialDiff generates a Phabricator resource that represents a diff between two revisions.
//
// The generated resource includes metadata about how the diff was generated, and a JSON representation
// of the changes from the diff, as parsed by Phabricator.
func (arc Arcanist) createDifferentialDiff(repo repository.Repo, mergeBase, revision repository.Revision, req request.Request, priorDiffs []string) (*differentialDiff, error) {
	revisionDetails, err := repo.GetDetails(revision)
	if err != nil {
		return nil, err
	}
	changes, err := arc.getDiffChanges(repo, mergeBase, revision)
	if err != nil {
		return nil, err
	}
	createRequest := differentialCreateDiffRequest{
		Branch:                    abbreviateRefName(req.ReviewRef),
		SourceControlSystem:       "git",
		SourceControlBaseRevision: string(mergeBase),
		SourcePath:                repo.GetPath(),
		LintStatus:                "4", // Status code 5 means "linter skipped"
		UnitStatus:                "4", // Status code 5 means "unit tests have been skipped"
		Changes:                   changes,
	}
	var createResponse differentialCreateDiffResponse
	runArcCommandOrDie("differential.creatediff", createRequest, &createResponse)
	if createResponse.Error != "" {
		return nil, fmt.Errorf(createResponse.ErrorMessage)
	}

	localCommits := make(map[string]interface{})
	for _, priorDiff := range priorDiffs {
		diffID, err := strconv.Atoi(priorDiff)
		if err != nil {
			return nil, err
		}
		queryRequest := differentialQueryDiffsRequest{[]int{diffID}}
		var queryResponse differentialQueryDiffsResponse
		runArcCommandOrDie("differential.querydiffs", queryRequest, &queryResponse)
		if queryResponse.Error != "" {
			return nil, fmt.Errorf(queryResponse.ErrorMessage)
		}
		priorProperty := queryResponse.Response[priorDiff].Properties
		if priorPropertyMap, ok := priorProperty.(map[string]interface{}); ok {
			if localCommitsProperty, ok := priorPropertyMap["local:commits"]; ok {
				if priorLocalCommits, ok := localCommitsProperty.(map[string]interface{}); ok {
					for id, val := range priorLocalCommits {
						localCommits[id] = val
					}
				}
			}
		}
	}
	localCommits[string(revision)] = *revisionDetails
	localCommitsProperty, err := json.Marshal(localCommits)
	if err != nil {
		return nil, err
	}
	if err := arc.setDiffProperty(createResponse.Response.ID, "local:commits", string(localCommitsProperty)); err != nil {
		return nil, err
	}
	if err := arc.setDiffProperty(createResponse.Response.ID, "arc:unit", "{}"); err != nil {
		return nil, err
	}

	return &createResponse.Response, nil
}