There are really a lot of ways to go about this, but the main ones I'll point out are:
#1 Single Release Pipeline with multiple stages/triggers
You were correct in thinking Manual deployment could work here using the various stages and branching out. (See Screenshot link below)
Release Pipeline with manual deployment paths
In this scenario DEV is deployed as soon as there is a new Release, then you can manually specify which path you want the rest of deployments to go (straight to Prod, or Test to Prod).
#2 Release Pipeline with pre-approvals
This is probably a little cleaner than the manual deployment and has the plus of being able to specify specific users or a group. (Link to screenshot below)
Release Pipeline with Pre-Approval condition
#3 Separate release pipelines executed based on build tag
After testing this I confirmed you are able to trigger varying releases based upon tagging specified in the Build Pipeline. I believe you can do the same for pull requests
Based on this tagging, it can determine through the Continuous Deployment filter process which release pipeline to run.
The Screenshot and steps below are the steps needed to make this work:
- Create Build Pipeline that includes whatever you need to successfully build, plus a Pipeline Variable (mine is ProdOnly_TestThenProd) that will be used to Specify the build tag name, and a Az Powershell task which will be used to set the Build tag on the build during execution. Here is the code for inline Script:
Write-Host "##vso[build.addbuildtag]$env:ProdOnly_TestThenProd"
Refer to this gif for reference: Build Pipeline
- Create two release pipelines one for DEV>PROD and another for DEV>TEST>PROD. Once created enable Continuous Deployment on Build and Add Branch/Tag filter based on your build pipeline branch/tag set. Refer to this screenshot: Release Pipelines
- Run the build pipeline manually and this will allow you to set the value of the pipeline variable at runtime, This allows you to specify which release pipeline you want to run in a one off situation, otherwise, the build pipeline can run with whatever the current variable value is in the Continuous Integration process. refer to this gif for illustration: Build Pipeline execution and Continuous Deployment
I like this #3 option because it allows you to have CI/CD cycle, but also if you need to run a one off pipeline, maybe release straight to Prod or some other stage, then it gives you flexibility to do so without a ton of manual work. Hopefully this answers your question.