2

Goal: Whenever a pull-request is approved and reviewer completes(merges) the pull request in azure repos, I want to determine the list of files in that merge request. Based on the file extensions, I have to trigger the respective build pipeline.

Issue: As of now it doesn't seem possible from azure devOps portal and I need REST APIs to do so. Please point me to API/APIs which help me determine list of changed files in a merge-request

Analysis: I have also seen Get Merge Requests but not sure where to get the mergeOperationId in the pipeline.

humblebee
  • 1,044
  • 11
  • 25

3 Answers3

4

As workaround, you can find completed PRs and check their commits. Example with GitHttpClient of .NET client libraries for Azure DevOps Services .

private static void ViewPullRequests(string TeamProjectName, string GitRepo, bool ClosedPRs = false, string TargetRef = "")
{
    if (ClosedPRs && TargetRef == "")
    {
        Console.WriteLine("Define a target branch reference");
        return;
    }

    var pullRequests = (ClosedPRs)? 
        GitClient.GetPullRequestsAsync(TeamProjectName, GitRepo, new GitPullRequestSearchCriteria { Status = PullRequestStatus.Completed, TargetRefName = TargetRef }, top: 10).Result : 
        GitClient.GetPullRequestsAsync(TeamProjectName, GitRepo, null ).Result;

    foreach (var pullRequest in pullRequests)
    {
        var commits = GitClient.GetPullRequestCommitsAsync(TeamProjectName, GitRepo, pullRequest.PullRequestId).Result;

        foreach (var commit in commits)
        {
            Console.WriteLine("{0} {1}", commit.CommitId.Substring(0, 8), commit.Comment);
            GitCommitChanges changes = GitClient.GetChangesAsync(TeamProjectName, commit.CommitId, GitRepo).Result;

            foreach(var change in changes.Changes)
                Console.WriteLine("{0}: {1}", change.ChangeType, change.Item.Path);
        }
    }
}

Rest Api methods:

  1. Pull Requests - Get Pull Requests

  2. Pull Request Commits - Get Pull Request Commits

  3. Commits - Get Changes

Shamrai Aleksander
  • 13,096
  • 3
  • 24
  • 31
4

One issue with the solution provided by Shamrai Aleksander is that the set of changes that you would collect by running GetChangesAsync() in a loop would include changes that have been merged into your pull request from merge commits. As a result, the set of changed files would be much larger than the true set of files changed within the pull request you are analyzing.

You can retrieve the set of files that have been changed only by the selected pull request by using the GetCommitDiffsAsync() method in the .NET client library (this maps to the Get Diff REST API). What's unique about this method/API is that if diffCommonCommit is true, it will perform a diff from the "merge base" of the target branch. This avoids the problem of extra files showing up due to merge commits in your pull request.

You will need the commit IDs for the latest commits both your pull request branch and the branch your pull request is targeting. Here is an example of a method that detects if a file with a certain path has been changed in a pull request.

public static async Task<bool> DoesPullRequestChangelistContainPath(
        string repositoryId,
        GitPullRequest pullRequest,
        string path)
    {
        // Get commit ID for production branch
        var productionBranch = await GitClient.GetBranchAsync(
            Constants.ProjectName,
            repositoryId,
            Constants.ProductionBranchName);
        var productionBranchCommitId = productionBranch.Commit.CommitId;

        // Get commit ID for PR branch
        var pullRequestSourceBranchNameWithoutPrefix = pullRequest.SourceRefName.Replace(Constants.AdoBranchPrefix, string.Empty);
        var pullRequestBranch = await GitClient.GetBranchAsync(
            Constants.ProjectName,
            repositoryId,
            pullRequestSourceBranchNameWithoutPrefix);
        var pullRequestBranchCommitId = pullRequestBranch.Commit.CommitId;

        // Get the diff between the merge base of the two branches and the latest commit of the pull request branch.
        // This gets us the set of changes between the "squashed" commits of the pull request and the production branch.
        var response = await GitClient.GetCommitDiffsAsync(
            repositoryId,
            diffCommonCommit: true,
            baseVersionDescriptor: new GitBaseVersionDescriptor() { Version = productionBranchCommitId, VersionType = GitVersionType.Commit},
            targetVersionDescriptor: new GitTargetVersionDescriptor { Version = pullRequestBranchCommitId, VersionType = GitVersionType.Commit });

        return response.Changes.Any(change => change?.Item?.Path?.Contains(path) == true);
    }
3

You can get list of changed files in merge request from the UI page.

enter image description here

If you want to get a list of changed files through the rest api, then you need to use the method provided by Shamrai Aleksander.

First you need to use the Pull Request Commits rest api to get the pull request Commits.

GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/commits?api-version=5.1

Then according to the Commits-Get Changes rest api to read the path parameter to get the changed files, and get the list of changed files in a loop.

GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits/{commitId}/changes?api-version=5.1

enter image description here

Hugh Lin
  • 17,829
  • 2
  • 21
  • 25