Search code examples
azure-pipelinesazure-devops-rest-apiazure-api-apps

Azure DevOps Services REST API 5.1 - get unit testing (VSTest) and sonarqued


I'm creating a script in ISE powershell to get information from the projects in azure devops. Some apis that I already use in my script are the following:

  1. ApiUri = "$projectUri/_apis/tfvc/branches?$apiVersion"
  2. ApiUri = "$projectUri/_apis/distributedtask/deploymentgroups?$apiVersion-preview"
  3. ApiUri = "$projectUri/_apis/pipelines?$apiVersion-preview"
  4. ApiUri = "$projectUri/_apis/git/repositories?$apiVersion"
  5. ApiReleasePipelinesUri = "$projectUri/_apis/release/definitions?$apiVersion"

An example of what I'm getting with the above apis is:

enter image description here

In the value, if it is 1 or more, the information of that process goes.

Now I want to extract the information about the unit testing (Visual studio test) and sonarqued.

I would like to have something like this for the case of sonarqued and unittesting. 0 if there was never such an implementation and 1 if unit testing and sonarqued were applied.

I can't find something similar to what I need, if someone could guide me or know how to extract that information it would help me

Used this task for unit tests: enter image description here

Used this task to sonarqued: enter image description here


Solution

  • This is relatively complex task and I have done similar thing for governance purposes (eg. find out which project is using specific task in their pipelines).

    This is only my view how I have resolved similar task.

    For this, you will have to use undocumented API to get all available tasks in your project collection. There are bunch of data that are returned, though you need task ID for next steps. (change the {project_collection}) https://dev.azure.com/{project_collection}/_apis/distributedtask/tasks

    In my scripts I use this functions to return all task names with their IDs written in Powershell:

    $ORG = "https://dev.azure.com/YOUR_PROJECT_COLLECTION/"
    $ADOAH = # Define your authentication header
    
    # Get all tasks
    Function Get-Tasks {
        $tasks = Get-API -url "$($ORG)_apis/distributedtask/tasks"
        $tasks = ConvertFrom-Json $tasks -AsHashTable
        $taskarray = @{}
        foreach ($task in $tasks.value) {
            $taskarray.Set_Item($task.name, $task.id) }
        return $taskarray
    }
    
    # Search for Task ID
    Function Get-TaskId {
        param (
            [parameter(mandatory)] $taskname
        )
        $tasks = Get-Tasks
        if ($taskname -match '^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$' -and $tasks.ContainsValue("$taskname")) {
            return $taskname }
        elseif ($null -eq $tasks."$taskname") {
            throw "Task name or ID does not exist!" }
        else { 
            return $tasks."$taskname" }
    }
    
    # Function to call API
    Function Get-API {
        param (
            [parameter(mandatory=$true)] [string] $url
        )
        Invoke-RestMethod -Uri $url -Method get -Headers $ADOAH
    }
    

    Second, if you have only classic pipelines, then the task is relatively easy and follow Scenario A. If you have also YAML pipelines, you will have to make the script even more complex, follow Scenario B.

    Scenario A: For the classic pipelines you need to get the URL of each pipeline. The JSON will return all jobs with respective tasks. You can scan the output and match with the task ID described in step 1. Please note, that if you have multiple jobs in single pipeline, you have to scan each job individually.

    Scenario B: From JSON return of each pipeline you can determine if it is classic or YAML pipeline by reading PipelineConfiguration - Type. https://learn.microsoft.com/en-us/rest/api/azure/devops/pipelines/pipelines/get?view=azure-devops-rest-7.0#pipelineconfiguration

    Usually, the result is YAML for YAML pipeline and designerJson for classic pipeline. For classic pipeline follow Scenario A. For YAML pipeline you have to read the content of YAML file and search for the task name in YAML format. You are not searching now for the ID of the task. Tricky part is, that when there are templates and extends used in pipeline, you have to cover them in your script logic and recursively scan them too.

    There might be easier way how to do it, though this worked for me.