1

When doing configuration-as-code and/or infrastructure-as-code, the problem often is that something being committed in the version control does not mean it is also applied on the environment. But there is a way to ensure it (except for very untimely network failures): push the intended changes in a branch and have the CD server apply the configuration and push it in master if and only if it applies.

So I have found a way to set up the DevOps repository so that a pull-request can only be merged if a build succeeded (1). And such build is useful for validating the syntax and previewing the changes (tf plan, kubectl diff and similar).

But then I still need to actually complete the pull request from the build.

Ensuring the PR can't be completed in any other way can probably be done with the policy or permissions, and ensuring the pull request is otherwise ready (reviewed) can be done by replacing the review approvals with approvals in the pipeline.

Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • 1
    While the general direction of what you seek is understandable, you haven't worded what you seek in an actual question. I take it you are asking "how can I make sure that a PR gets accepted only after I have validated the end result of the merge" ? – LeGEC Aug 26 '22 at 14:32
  • @LeGEC, no, that would be trivial (and answered by the linked question). What I am asking is how to make sure the PR gets accepted if and only if it actually gets deployed. Because what is deployed matters more than what is in the repository, and the desire is for the two to be always in sync. – Jan Hudec Aug 30 '22 at 15:59

4 Answers4

1

Completing an Azure DevOps Pull Request "if and only if" a build succeeds is an interesting question. I believe it's possible.

The "only if" part is easy; simply turn on branch policies for the target branch (master in your case). It doesn't actually matter what policy you enable, as long as it's something a user can't achieve. For example, you could set the minimum number of reviewers to 10, or you could add a required reviewer which is an account no one can impersonate, or you can require a build or status policy, or you can use some combination of these. Basically you just need to make sure no one can complete a PR into this branch unless they have the bypass security setting. (So obviously don't give anyone that privilege either.)

Now for the "if" part; you could add a post build step which completes the PR with bypass using the API. (Here's a possible working example from the AzureDevOps dev forum.) Using the bypass should force complete the PR with two possible exceptions that I can think of:

  1. A user could abandon the PR.
  2. A user could vote to reject the PR. (Or select "Waiting for Author".)

Even these could likely be overcome via the API, but presumably if one of these occurs the user likely has a good reason and you probably don't want the PR to complete anyway.

TTT
  • 22,611
  • 8
  • 63
  • 69
0

The solution I can think if is a combination of the following:

  1. In your build pipeline, set the completion status of the pull request to auto complete, by calling the Azure DevOps REST API and setting the AutoCompleteSetBy.Id to whoever user you want. This will auto-enable the autocomplete on the pipeline.
  2. In the branch policies for the merge to the target branch (in your case master), add a merge policy requirement that requires your build pipeline to be successful to allow a merge of your PR.

This will result in:

  • Your pipeline will auto-complete once all branch policy checks are successful.
  • Your build pipeline is required to be successful for the pipeline to complete.
Bast
  • 373
  • 3
  • 10
0

It does not handle the completely general case, but for running terraform there is Atlantis.

The way it works is that it watches the pull requests, and on a special comment (atlantis apply) it executes terraform apply and if it succeeds (and if it's configured that way) it merges the pull request. So then if only the technical user it runs under is given permission to commit&push to master, it does the right thing.

Approximately the same workflow can be used with builds. An identity can be given to that specific pipeline to merge the PR and do merges by triggering the build.

But the main motivating use-case for this is infrastructure-as-code, and infrastructure-as-code is mainly terraform anyway, so this should handle large part of the practical uses.

Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
-1

You can always have your pipeline run the merge :

  • instead of running your tests on the HEAD commit of the branch,
  • have your job switch to your target branch, run git merge <commit>, and run your tests on that.
LeGEC
  • 46,477
  • 5
  • 57
  • 104
  • And will that make the merge request appear merged? – Jan Hudec Aug 26 '22 at 14:53
  • no, my idea was to just run `git merge` on the testing machine, but not push the result. You should accept the merge request separately. – LeGEC Aug 26 '22 at 17:20
  • That's what is already happening automatically. But the point of the question is that it must not be possible to do one without the other. Pushing the result is acceptable solution (it's how it's supposed to work, really), but the PR needs to end up in merged state—which I am not sure it will. – Jan Hudec Aug 26 '22 at 22:42
  • For the technical side of things : you could allow only one specific user account to accept merge requests, and use an API key linked to that account to accept merge requests only after validation, but I wouldn't recommend placing that API key only on an integration server. I would rather suggest to make sure you have a reliable way to roll back if there is an issue, and adopt a more standard integration process (e.g. : the merge button turns green only if the validation job is ok) – LeGEC Aug 29 '22 at 13:54
  • Also : what kind of activity to you have on that repository ? (how many people are working on it ? how many parallel features can you have ? is the rate of merges 1 per week ? 1 per day ? several per day ? ...) – LeGEC Aug 29 '22 at 13:56
  • It is **infrastructure-as-code**, so fundamentally there cannot be parallel features. And even more fundamentally there **is no way to rollback**. The repository isn't the source of truth, so I need it to, reasonably reliably, track it. Well, there is a way to roll back, but that applies to intentionally reverting changes. If things get out of sync, we don't know we should revert. – Jan Hudec Aug 29 '22 at 14:09