Functions/Add-AzDoUserStoryWorkItem.ps1
|
Function Add-AzDoUserStoryWorkItem{ <# .SYNOPSIS Creates a work item of the type User Story .DESCRIPTION Creates a work item of the type User Story .EXAMPLE Add-AzDoUserStoryWorkItem -Project "Alpha Devs" -Title "New Story Item" .EXAMPLE This example first get details from another work item, and uses those to place a new item on the same board. This also uses <br> to break lines in the descrption field. $WItem = Get-AzDoUserStoryWorkItem -Project $TeamName -WorkItemID 123456 Add-AzDoUserStoryWorkItem -Project $TeamName -Title "Important Scripting work" -Board $WItem.fields.'System.AreaPath' -Description "Important work <br> Line 2" -AssignedTo $WItem.fields.'System.AssignedTo'.displayName -Verbose -Tags "Tag1","Tag2" -AcceptanceCriteria "Accepted" .PARAMETER Project The name of your Azure Devops Project or Team .PARAMETER WorkItemTitle The name of your Azure Devops Project or Team .PARAMETER Board The name of your Azure Devops Board you want to add the item to .PARAMETER StoryType The type of work item to create. Valid values can be retrieved by running the Get-AzDoWorkItemTypes command. .PARAMETER Iteration The name of the iteration path to assign the work item to. This is often in the format "Project\IterationName". If not specified, the work item will not be assigned to any iteration. .PARAMETER Description The content of the description field. Lines can be broken by adding <br> .PARAMETER AcceptanceCriteria The content of the Acceptance Criteria field. Lines can be broken by adding <br> .PARAMETER Priority This is the priority of the item. Default is 3. .PARAMETER AssignedTo This is the person the item is assigned to. .PARAMETER OriginalEstimate How much time is the task expected to take .PARAMETER ExtraParameters Additional parameters to include when creating the work item. This should be a hashtable where the key is the field reference name and the value is the value to set. .PARAMETER Tags Tags assigned to the work item. These are separated by commas, i.e. "Tag1","Tag2" .INPUTS Input is from command line or called from a script. .OUTPUTS This will output the created work item details. .LINK https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work-items/create .NOTES Author: Lars Panzerbjørn Creation Date: 2020.07.31 #> [CmdletBinding(PositionalBinding=$False)] param( [Parameter()] [Alias('TeamName')] [string]$Project = $Script:Project, [Parameter(Mandatory)] [Alias('Title')] [string]$WorkItemTitle, [Parameter(Mandatory)] [string]$Board, [Parameter(Mandatory, HelpMessage = "The type of work item to create. Valid values can be retrieved by running the Get-AzDoWorkItemTypes command.")] [Alias('StoryType')] [string]$WorkItemType, [Parameter()][string]$Iteration, [Parameter()][string]$Description, [Parameter()][string]$AcceptanceCriteria, [Parameter()][ValidateSet(1,2,3,4)][string]$Priority = 3, [Parameter()][string]$AssignedTo, [Parameter()][int]$OriginalEstimate, [Parameter()] [hashtable[]]$ExtraParameters, [Parameter()][string[]]$Tags ) BEGIN{ Write-Verbose "Beginning $($MyInvocation.Mycommand)" $Uri = $BaseUri + "$Project/_apis/wit/workitems/`$$($WorkItemType)?api-version=7.1" Write-Verbose "URI is $Uri" } PROCESS{ Write-Verbose "Processing $($MyInvocation.Mycommand)" $Body = @([pscustomobject]@{ op = "add" path = '/fields/System.Title' value = $WorkItemTitle } ) $Body += @([pscustomobject]@{ op = "add" path = '/fields/System.AreaPath' value = $Board } ) $Body += @([pscustomobject]@{ op = "add" path = '/fields/Microsoft.VSTS.Common.Priority' value = $Priority } ) IF($AssignedTo){ $Body += @([pscustomobject]@{ op = "add" path = '/fields/System.AssignedTo' value = $AssignedTo } ) } #This may need to have project added in front of the iteration. A bit of a ToDo for future enhancement. IF($Iteration){ $Body += @([pscustomobject]@{ op = "add" path = '/fields/System.IterationPath' value = $Iteration } ) } IF($Description){ $Body += @([pscustomobject]@{ op = "add" path = '/fields/System.Description' value = $Description } ) } IF($AcceptanceCriteria){ $Body += @([pscustomobject]@{ op = "add" path = '/fields/Microsoft.VSTS.Common.AcceptanceCriteria' value = $AcceptanceCriteria } ) } IF($OriginalEstimate){ $Body += @([pscustomobject]@{ op = "add" path = '/fields/Microsoft.VSTS.Scheduling.OriginalEstimate' value = $OriginalEstimate } ) } IF($Tags){ # ForEach ($Tag in $Tags) {$CombiTag += "$Tag;"} $CombiTag = ($Tags -join ';') + ';' $Body += @([pscustomobject]@{ op = "add" path = '/fields/System.Tags' value = $CombiTag } ) } IF($ExtraParameters){ ForEach ($KV in $ExtraParameters){ ForEach ($Key in $KV.Keys){ $Body += @([pscustomobject]@{ op = "add" path = "/fields/$Key" value = $KV[$Key] } ) } } } $Body = ConvertTo-Json $Body Write-Verbose -Message $Body Write-Verbose -Message "$Uri" $StatusCode = $null $Response = Invoke-RestMethod -Uri $Uri -Method POST ` -Headers $Header ` -ContentType "application/json-patch+json" ` -Body $Body ` -StatusCodeVariable StatusCode ` -SkipHttpErrorCheck IF($StatusCode -ge 400) { # This should output exactly *what* ADO is expecting but not getting. IF($Response.customProperties.RuleValidationErrors) { ForEach ($Rule in $Response.customProperties.RuleValidationErrors) { #Write-Warning "Missing/invalid field: $($Rule.fieldReferenceName). Supply it via -ExtraParameters @{ '$($Rule.fieldReferenceName)' = 'value' }" Write-Error "Missing/invalid field: $($Rule.fieldReferenceName). Supply it via -ExtraParameters @{ '$($Rule.fieldReferenceName)' = 'value' }" # THROW "Missing/invalid field: $($Rule.fieldReferenceName). Supply it via -ExtraParameters @{ '$($Rule.fieldReferenceName)' = 'value' }" } } # Write the full error object as readable JSON # ($Response | ConvertTo-Json -Depth 10) -split "`n" | ForEach-Object { # Write-Error $_ # } RETURN } RETURN $Response } } |