Ga naar inhoud

Aanmaken standaard tasks

Omdat het handig is standaard (DoD) taken aan te maken bij een User Story zodat je niks vergeet, dit script controleert alle User Stories in de huidige Iteration en maakt voor deze stories de benodigde tasks aan.

Benodigdheden

  1. PAT token van je DevOps project
  2. Project en organisatie naam.
  3. Een manier om je powershell script te automatiseren, dit kan door een scheduled task, scheduled pipeline of bijvoorbeeld een webhook.

Script

Het script maakt gebruik van de DevOps API om taken aan te maken, de taken worden gedefineerd in een json bestand, zorg dat dit bestand in dezelfde locatie als het script staat.

workitems.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[
    {
        "Title": "Documentatie",
        "Description": "Beschrijf de wijzigingen of nieuwe functionaliteit op https://docs.loevencloud.nl"
    },
    {
        "Title": "Stappenplan",
        "Description": "defineer een stappenplan."
    },
    {
        "Title": "Testen",
        "Description": "Beschrijf testen en implementeer deze waar mogelijk."
    },
    {
        "Title": "Onderzoek",
        "Description": "Ga er op uit en doe onderzoek."
    },
    {
        "Title": "Automatiseer",
        "Description": "Kan het automatisch?."
    },
    {
        "Title": "Integreer",
        "Description": "integreert het in de huidige setup (https://docs.loevencloud.nl"
    }
]
automateTasks.ps1
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
<#
.SYNOPSIS
Automation script for common devops tasks
#>
[CmdletBinding()]
param (
    [Parameter()]
    [string]$org = "DEVOPSORG",
    [Parameter()]
    [string]$project = "DEVOPSPROJECT",
    [Parameter()]
    [string]$pat = "DEVOPSPAT"    
)
#Global Variables
$B64Pat = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("`:$Pat"))
$header = @{
    Authorization = "Basic $B64pat"
}
$iterationBaseUri = 'https://dev.azure.com/ORG/PROJECT/_apis/work/teamsettings/iterations?$timeframe=current&api-version=7.0'
$iterationUri = $iterationBaseUri.replace("ORG/PROJECT","$org/$project")
$workItemBasePostUri = 'https://dev.azure.com/ORG/PROJECT/_apis/wit/workitems/$Task?api-version=6.1-preview.3'
$workItemPostUri = $workItemBasePostUri.replace("ORG/PROJECT", "$org/$project")
$currentIteration = Invoke-RestMethod -Method GET -Headers $header -Uri $iterationUri -ContentType "application/json"
$workitemsUri = "https://dev.azure.com/$org/$project/_apis/work/teamsettings/iterations/$($currentIteration.value.id)/workitems?api-version=7.0"
$allWorkitems = Invoke-RestMethod -Method GET -Headers $header -Uri $workitemsUri -ContentType "application/json"
$defaultWorkItems = Get-Content -Raw -Path /scripts/workitems.json | ConvertFrom-Json
$userStories = $allWorkitems.workItemRelations | Where-Object { $_.source -eq $null }
$excludedStories = @("OPS", "OOTS")

#Functions
function Add-devOpsWorkItem {
    [CmdletBinding()]
    param (
        [Parameter()]
        [string]$Title,
        [Parameter()]
        [string]$userStoryId,
        [Parameter()]
        [string]$description,
        [Parameter()]
        [string]$iterationPath        
    )
    $body = @(
        @{
            op    = "add"
            path  = "/fields/System.IterationPath"
            value = "$iterationPath"
        },
        @{
            op    = "add"
            path  = "/fields/System.Title"
            value = "$title"
        },
        @{
            op    = "add"
            path  = "/fields/System.Description"
            value = "$description"
        },
        @{
            op    = "add"
            path  = "/relations/-"
            value = @{
                rel = "System.LinkTypes.Hierarchy-Reverse"
                url = "https://dev.azure.com/$org/$project/_apis/wit/workitems/$userStoryId"
            }
        }
    ) | ConvertTo-Json -Depth 10
    $response = Invoke-RestMethod -Uri $workItemPostUri -Headers $header -Method POST -Body $body -ContentType "application/json-patch+json"

    if ($response.id) {
        Write-Host "`tTask $title created and linked"
    }
    else {
        Write-Host "Error creating task and linking to user story: $($response | ConvertTo-Json -Depth 10)"
    }
}

# Main script
foreach ($userStory in $userStories) {
    $storyProperties = Invoke-RestMethod -Method get -Headers $header -Uri $userstory.target.url -ContentType "application/json"
    $iteration = $($storyProperties.fields.'System.IterationPath')
    Write-Output "$iteration - $($storyProperties.fields.'System.Title')"
    if ($excludedStories -contains $($storyProperties.fields.'System.Title')) {
        Write-Output "$($storyProperties.fields.'System.Title') is excluded for default work process."
    }
    else {
        $childItems = $allWorkitems.workItemRelations | Where-Object { $_.source.id -eq $userstory.target.id }
        $activeTasks = @()
        foreach ($child in $childItems) {
            $taskMeta = @{} | Select-Object Title
            $childProperties = Invoke-RestMethod -Method get -Headers $header -Uri $child.target.url -ContentType "application/json"
            $taskMeta.Title = "`t$($childProperties.fields.'System.Title')"
            $activeTasks += $taskMeta
        }
        foreach ($defaultTask in $defaultWorkItems) {
            if (!($activeTasks.Title -match $defaultTask.Title)) { 
                Add-devOpsWorkItem -Title $defaultTask.Title -userStoryId $userstory.target.id -iterationPath $iteration -description $defaultTask.Description
            }
        }
    }
}