0
votes

We currently have the following branch strategy:

Develop > Release > Master

Devs create a local branch from Develop, make changes merge to develop. Our dev environment builds off that branch. When they want their changes tested they push to QA environment, which also uses the Develop branch. This cycle goes on until functional testing for the iteration is done. At that point the code is merged into the Release branch and is deployed through staging and then to prod. After deploying to prod the code should be merged to Master, but it's often forgotten about. This causes problems in niche scenarios.

Is there a way to use perhaps devops pipelines to conditionally raise a PR automatically? So I'm thinking this would need 2 PRs:

  1. PR raised for Master branch after successful release to prod. Idea here would be once sign off has been granted someone from the team can just approve.
  2. PR raised for Develop branch if the first PR is approved and the code in Master now differs from Develop. In a lot of cases it won't as therefore wouldn't need a PR.

I've been googling for this and found the api methods like this but I can't see how you could put this in a pipeline and make it conditional.

Additional Info:

My understanding is that the build definition needs to know what branch to build as per the image below. So, creating a new release branch every sprint would either result in having to update the build definition every time or creating a new build definition, that essentially would be a complete replica in most cases except for the branch name. Unless I'm misunderstanding, which I think I am.

enter image description here

1
Why don't you just do the sane thing that everyone else does: merge release back to master after that release is done?Ian Kemp
@IanKemp - I'd love for that to be trusted but we have multiple teams and sometimes it's missed. This ends up in complications where hotfixes need to go out via the release branch, whilst a planned change is already in the release branch. In this scenario a copy should be able to be taken from Master but as it wasn't merged this couldn't be done.sr28
Wait, you only have a single forever-living release branch? That defeats the entire purpose. Make a new release-<version> branch off master at the beginning of each new sprint (i.e. it will contain the previous sprint's work), put whatever hotfixes in there that need to go for that release as they come along during the sprint, and merge it back to master at the end of that sprint - then wash, rinse, repeat. You can easily write a start-new-sprint to automate this.Ian Kemp
What I'm trying to say is that this question seems like an X-Y problem: you have a problem with people forgetting to merge code back and you are trying to find an automated solution to remind them to do so. Such a solution is going to be non-trivial to write, fragile, and will require maintenance. Based on experience, your real problem seems like a convoluted branching strategy that allows for things to fall through the cracks, and/or devs lacking merge discipline. Those are completely different issues and trying to solve them with code is a band-aid on a bullet wound.Ian Kemp
@sr28 You don't need to make any updates to the builds definition. Running on which branch is not part of the builds definition, but only its runtime resources. You can refer to this REST API Runs - Run Pipeline. You can use the parameter resources to specify which branch the pipeline will run on without updating the pipeline.Jane Ma-MSFT

1 Answers

1
votes

The following PowerShell example creates a pull request from master to some target branch as a build task. You can add it to your release as an additional stage "Create PR to some branch" with one PowerShell task. Additionally, you can create periodically build to check diff and create pull requests.

$user = ""
$token = "$(System.AccessToken)"
$branchTarget = "$(Build.SourceBranch)"
$branchSource = "refs/heads/master"
$branchTragetPath = $branchTarget -replace "refs/heads/", ""
$teamProject = "$(System.TeamProject)"
$repoName = "$(Build.Repository.Name)"
$orgUrl = "$(System.CollectionUri)"

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
 
$uriBranchStatus = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/stats/branches?name=$branchTragetPath&api-version=5.1"
$uriCheckActivePR = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/pullrequests?searchCriteria.targetRefName=$branchTarget&searchCriteria.sourceRefName=$branchSource&api-version=5.1"
$uriCreatePR = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/pullrequests?api-version=5.1"

$resultStatus = Invoke-RestMethod -Uri $uriBranchStatus -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

if ($resultStatus.behindCount -eq 0)
{
    Write-Host "Current branch contains last changes from master"
    Return
}

$resultActivePR = Invoke-RestMethod -Uri $uriCheckActivePR -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

if ($resultActivePR.count -gt 0) 
{
    Write-Host "PR exists already"
    Return
}

$bodyCreatePR = "{sourceRefName:'$branchSource',targetRefName:'$branchTarget',title:'Sync changes from $branchSource'}"

$result = Invoke-RestMethod -Uri $uriCreatePR -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $bodyCreatePR

Write-Host "Created PR" $result.pullRequestId