Apply Extensible Pull Request Policies to VSTS to Support the Development Process

 
3r3-31. 3r33333. Often, as part of the Pull Request check, in addition to the code review itself, there is a need to perform a set of routine checks. Some checks may concern PR design. Others are to check related conditions that form the basis of the change acceptance process. 3r33333.  
If routine checks are not automated, a person can start to forget or bypass them. Because routine is boring.
3r33333.  
3r33333. Visual Studio Team Services offers a fairly convenient infrastructure for handling pull requests. These include customizable merge builds policies, the appointment of reviewers, and the rules for merging changes that are accepted. All this is supplemented with a convenient system for discussing and commenting on the code.
3r33333.  
3r33333. External plug-in policies are a powerful tool for expanding the pull request process. 3r33333.  
About their creation and use and talk (and see the code)
Create . In addition to the result and context, you must pass the text that the user sees. Additionally, you can send the URL: in this case, the status label on the PR form will become a link and the user can go to the page with the status details.
3r33333.  
3r33333. Calling the method results in creating a new PR status record. Within one context, the last added status value is considered active. Earlier status records are not visible from the UI interface, but they can be obtained using the 3r3386 method. List
.
3r33333.  
3r33333. For the status of the statuses in the previous picture, the real list of statuses for the pull-request can be as follows:
3r33333.  
3r3208. {
"value":[
{
"id": 1,
"state": "failed",
"description": "PR title format",
"context": "@{name=check-title; genre=my-pr-policy}",
"creationDate": "2018-11-06T18:35:57.0324172Z",
"updatedDate": "2018-11-06T18:35:57.0324172Z",
"createdBy": "Masked value",
"targetUrl": null
},
{
"id": 2,
"state": "failed",
"description": "Build for last update",
"context": "@{name=check-build; genre=my-pr-policy}",
"creationDate": "2018-11-06T18:35:57.5167963Z",
"updatedDate": "2018-11-06T18:35:57.5167963Z",
"createdBy": "Masked value",
"targetUrl": null
},
{
"id": 3,
"state": "succeeded",
"description": "No offset from develop",
"context": "@{name=check-offset; genre=my-pr-policy}",
"creationDate": "2018-11-06T18:35:57.782379Z",
"updatedDate": "2018-11-06T18:35:57.782379Z",
"createdBy": "Masked value",
"targetUrl": null
},
{
"id": 4,
"state": "succeeded",
"description": "PR title format",
"context": "@{name=check-title; genre=my-pr-policy}",
"creationDate": "2018-11-06T18:46:37.2627154Z",
"updatedDate": "2018-11-06T18:46:37.2627154Z",
"createdBy": "Masked value",
"targetUrl": null
},
{
"id": 5,
"state": "succeeded",
"description": "Build for last update",
"context": "@{name=check-build; genre=my-pr-policy}",
"creationDate": "2018-11-06T18:51:33.7920543Z",
"updatedDate": "2018-11-06T18:51:33.7920543Z",
"createdBy": "Masked value",
"targetUrl": null
},
{
"id": 6,
"state": "failed",
"description": "PR title format",
"context": "@{name=check-title; genre=my-pr-policy}",
"creationDate": "2018-11-06T18:53:44.3075889Z",
"updatedDate": "2018-11-06T18:53:44.3075889Z",
"createdBy": "Masked value",
"targetUrl": null
},
{
"id": 7,
"state": "failed",
"description": "Title format is not correct",
"context": "@{name=check-title; genre=my-pr-policy}",
"creationDate": "2018-11-06T19:26:11.3019433Z",
"updatedDate": "2018-11-06T19:26:11.3019433Z",
"createdBy": "Masked value",
"targetUrl": null
}
],
"count": 7
}
3r33333.  
3r33333. After viewing the list of current statuses, you can update the selected by the index in the list. For this is the method Update .
3r33333.  
3r33333. Finally, status records can be deleted using the 3r3182 method. Delete
.
3r33333.  
3r33333. A history of PR status changes may be useful for further analysis. Therefore, we use the following method of status changes:
3r33333.  
3r3191.  
3r33333. Find the most recent status record of the same context
 
3r33333. If she has the same result values, descriptions and links that we want to add, we do nothing
 
3r33333. Otherwise, add a new status record. 3r33333.  
This allows you to keep a history of changes, not much inflating it.
 
3r3204. 3r33333.  
3r3208. function Set-PullRequestStatus {3r3333359. param (
[Parameter (Mandatory = $true)]
[string]$ pullRequestId,
[Parameter (Mandatory = $true)]
[string]$ state,
[Parameter (Mandatory = $true)]
[string]$ description,
[Parameter (Mandatory = $true)]
[string]$ contextName;
$ b = @ {
state = $ state;
description = $ description;
context = @ {
name = $ contextName;
genre = $ contextGenre;
};
targetUrl = $ targetUrl;
}
$ body = ConvertTo-Json $ b
#
# Get current list of statuses
#
$ endpoint = (Get-ProjectBaseURL) + "/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/statuses?api-version=4.1-preview.1" 3rr3359. $ res = Get-AzureRequestReqults -URI $ endpoint -context ($ context + @ {pullRequestId = $ pullRequestId})
#
# Try to find a context for a given context and name. Start looking from the last one. If found - check if it has the same values.
#
$ i = $ res.count
$ foundSameStatus = $ false
while ($ i -GT 0) {3r3333359. $ r = $ res.value[$i-1]
if (($ r.context.name -EQ $ contextName) -AND ($ r.context.genre -EQ $ contextGenre)) {3rr3359. $ foundSameStatus = ($ r.state -EQ $ state) -AND ($ r.description -EQ $ description) -AND ($ r.targetUrl -EQ $ targetUrl)
break
}
$ i--
}
$ res = $ r
#
# If the status /values ​​were not found - add new record.
#
if (-not $ foundSameStatus) {
$ endpoint = (Get-ProjectBaseURL) + "/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/statuses?api-version=4.1-preview.1" 3rr3359.
$ res = Get-AzureRequestReqults -URI $ endpoint -context ($ context + @ {pullRequestId = $ pullRequestId}) -method POST -query $ body
}
return @ {status = $ res; status_changed = $ (- not $ foundSameStatus)}
}
3r33333.  
Practical application
3r33333.  
3r33333. We have adopted a rather conservative approach to adopting changes in the integration branch. We try to test the change as far as possible on the feature branch.
3r33333.  
3r33333. Here are some tasks that we solve with the help of PR statuses within the framework of customizable policies:
3r33333.  
3r33232.  
3r33333. All PRy must be decorated in the same style. Therefore, the first control that was created is the design of the PR header. We check it for regular expression matching.
 
3r33333. The branch of PR should not lag behind the branch where it is being poured in (integration was performed).
 
3r33333. If within the framework of PR the database project files are changed, then auto test files must also be present.
 
3r33333. There is a successful build branch on the last change.
 
3r33333. Such an assembly was successfully rolled out to a test bench and autotests were completed.
 
3r33333. 3r33333.  
3r33333. The listed conditions can be checked manually. We did that before. But this is a routine, and it has been replaced by an automated process. Now we can supplement and change the set of checks - it will always be integrated into the process, always executed.
3r33333.  
3r33333. An additional huge plus is the politician - they are transparent for everyone, and always in sight - on the PR page. They no longer need to be reminded. 3r33333.  
In addition, for policies that have not passed the test, we show a link to our Wiki pages with a description of the policy and the expected actions.
3r33333.  
Technical implementation of policy implementation
3r33333.  
3r33333. At the moment, the logic of policies is implemented in the form of powershell scripts. Due to high-level cmdlets and a good data object model, the script code is very compact. And the ability to run the script step-by-step interactively and poking around in variables greatly simplifies the development and debugging process. 3r33333.  
By the way, after the release of powershell core - scripts can be run on other platforms (tested on MacOS).
3r33333.  
3r33333. Run scripts in a special VSTS release on a schedule about once every couple of hours. Maybe we will start to run through the scheduler more often. 3r33333.  
This approach, of course, gives a significantly slower response than if you implement the same in the form of the Azure Function and link it to VSTS via a web hook. But for us it was more important to implement the checks and see how it will work in the process (MVP). The speed of the checks is not important yet. This will be the next step.
3r33333.  
3r33333. The implementation of the VSTS REST API libraries used in the checks, plus a small example that implements some of these policies can be found in 3r3346. repositories on github
. I hope someone will be useful.
3r33333.
3r33352. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//mediator.mail.ru/script/2820404/"""_mediator") () (); 3r33333.
3r33333.
+ 0 -

Add comment