8
votes

I'm trying to create a YAML based pipeline that takes a parameter, then trigger the pipeline to run from a Azure DevOps REST API. I'm able to see the build gets queued, but the parameter was not overridden from my POST body.

My template my-template.yaml.

parameters:
    - name: testParam
      type: string
      default: 'N/A'


steps:
    - script: echo ${{ parameters.testParam }}

My pipeline yaml that extends the template.

trigger:
    - master

extends:
    template: my-template.yaml

Then I trigger this pipeline using the queue build REST API: https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=5.1 with a POST body as below.

{
    "parameters": "{\"testParam\": \"hello world\"}",
    "definition": {
        "id": 50642
    },
    "sourceBranch": "refs/heads/master"
}

So I'm expecting the pipeline execution will echo hello world instead of N/A. Unfortunately, I'm still seeing N/A in the pipeline results.

Anyone has idea of what happened? Am I miss anything?

5

5 Answers

10
votes

I ran into the exact same problem - a pipeline taking runtime parameters that worked when run via the UI, but not via the Queue Build REST API.

I was able to solve this by using an undocumented API, the exact same one that the Az DevOps Pipelines UI calls when running a pipeline:

https://dev.azure.com/{organization}/{project}/_apis/pipelines/{pipelineId}/runs?api-version=5.1-preview

With the following POST body:

{
  "stagesToSkip": [],
  "resources": {
    "repositories": {
      "self": {
        "refName": "refs/heads/master"
      }
    }
  },
  "templateParameters": {
    "testParam": "hello world"
   },
  "variables": {}
}

Note that with this API, your runtime parameters are being submitted as actual JSON, not stringified JSON, and under the key templateParameters.

As well, don't forget to include the standard headers one might expect for this call:

  • Content-Type: application/json
  • Accept: application/json
  • AUTHORIZATION: bearer $SYSTEM_ACCESSTOKEN.

Using this approach, in the called pipeline, you will always be able to access the value of ${{ parameters.testParam }} whether the pipeline is called via REST API or manually in the UI.

While you're correct that the value is accessible as $(testParam) when executed via REST API, that variable is not populated when running the pipeline in the UI.

As such, I'd recommend using this undocumented API, since the called pipeline can use ${{ parameters.testParam }} without regard to how it's being called. Of course, it's (as of writing) undocumented, so.... ¯_(ツ)_/¯

As well, it should be noted that your pipeline must be formatted as @Josh Gust suggested:

my-template.yaml:

parameters:
  - name: testParam
    type: string
    default: 'N/A'
steps:
  - script: echo ${{ parameters.testParam }}

azure-pipelines.yaml:

parameters:
  - name: testParam
    type: string
    default: 'N/A'
trigger:
  - master
extends:
  template: my-template.yaml
  parameters:
    testParam: ${{ parameters.testParam }}
1
votes

Got the solution after spending 2 to 3 Hour:

https://dev.azure.com/{organization}/{project}/_apis/pipelines/2/runs?api-version=6.0-preview.1

   Where 2= {pipelineId}

enter image description here

Header :

Authorization: Personal access token. Use any value for the user name and the token as the password.
Type: basic

Content-Type : application/json
Accept : application/json

Right Now I'm using: Postman for testing this API So sharing posting main screenshot: enter image description here enter image description here

In the Body part :

{"previewRun":false,"stagesToSkip": [],"resources": {"repositories": {"self": {"refName": "refs/heads/master"}}},"templateParameters": {"testParam": "rawat Rob" },"variables": {}}

previewRun :{If true, don't actually create a new run. Instead, return the final YAML document after parsing templates.}

It is working for me And having test around 5 to 7 time

0
votes

Looks like the parameters are not necessary in this case, I merged the yaml into one like below.

# File: azure-pipelines.yml
trigger:
    - master

steps:
    - script: echo $(testParam)

Note the difference between $(testParam) and ${{ parameters.testParam }}.

Then I trigger it from REST API and it works totally fine.

enter image description here

0
votes

You're not sending your parameter from your pipeline to the template.

Take a look at how the documentation says this should happen. I haven't tested but I think if you wire the parameter to the template properly, you'll get what you expect using the template.

Basically your template should look like this:

# File: simple-param.yml
parameters:
- name: yesNo # name of the parameter; required
  type: boolean # data type of the parameter; required
  default: false

steps:
    - script: echo ${{ parameters.yesNo }}

And your pipeline should be thus:

# File: azure-pipelines.yml
trigger:
- master

extends:
    template: simple-param.yml
    parameters:
        yesNo: false # set to a non-boolean value to have the build fail

Notice the parameters: yesNo: false

Also, the Runtime Parameters Documentation might suggest that you should define your pipeline parameters as explicit parameters.

0
votes

Seems that it's an issue in Azure DevOps Rest API: https://developercommunity.visualstudio.com/content/problem/1000544/parameters-to-api-rest-build-queue-method.html

​I encountered the same problem and noticed that the runtime parameter is introduced to the pipeline run as variable. Thus using $(MyParam) instead of ${{parameters.MyParam}} in the yaml fixes the problem.