From a564035f5f58017c8ae6a48a46b3fdd5123f8545 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 1 Apr 2016 15:54:20 +0200 Subject: [PATCH 001/102] Updated Set-JiraIssue to allow for optional Summary and Description --- PSJira/Functions/New-JiraIssue.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PSJira/Functions/New-JiraIssue.ps1 b/PSJira/Functions/New-JiraIssue.ps1 index bd7a78e9..345842b3 100644 --- a/PSJira/Functions/New-JiraIssue.ps1 +++ b/PSJira/Functions/New-JiraIssue.ps1 @@ -28,6 +28,7 @@ function New-JiraIssue [PSJira.Issue] The issue created in JIRA. #> [CmdletBinding()] + [OutputType('PSJira.Issue')] param( [Parameter(Mandatory = $true)] [String] $Project, @@ -38,10 +39,10 @@ function New-JiraIssue [Parameter(Mandatory = $true)] [Int] $Priority, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [String] $Summary, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [String] $Description, [Parameter(Mandatory = $false)] From de30fc666dd9d1b99671dcb313aac0ef438344eb Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 1 Apr 2016 15:56:40 +0200 Subject: [PATCH 002/102] Allow to set default credentials for all Jira* commands in the current session --- PSJira/Functions/Set-JiraConfigServer.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/PSJira/Functions/Set-JiraConfigServer.ps1 b/PSJira/Functions/Set-JiraConfigServer.ps1 index 1782db30..3817f92d 100644 --- a/PSJira/Functions/Set-JiraConfigServer.ps1 +++ b/PSJira/Functions/Set-JiraConfigServer.ps1 @@ -28,8 +28,21 @@ function Set-JiraConfigServer [String] $Server, [String] $ConfigFile + + [Parameter(Mandatory = $false)] + [PSCredential] $Credential ) + # Set default value for Parameter Credential for all commands in this Module + if ($Credential) + { + [System.Collections.ArrayList]$commandList = Get-Command -Noun Jira* | Where-Object {$_.Name -ne 'Set-JiraConfigServer'} + foreach ($cmd in $commandList) + { + $global:PSDefaultParameterValues["${cmd}:Credential"] = $Credential + } + } + # Using a default value for this parameter wouldn't handle all cases. We want to make sure # that the user can pass a $null value to the ConfigFile parameter...but if it's null, we # want to default to the script variable just as we would if the parameter was not From 8522dbfa3ece69dc3be613a404b1c4774286b723 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 4 May 2016 13:53:25 +0200 Subject: [PATCH 003/102] Added draft of Set-JiraIssueLink --- PSJira/Functions/Set-JiraIssueLink.ps1 | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 PSJira/Functions/Set-JiraIssueLink.ps1 diff --git a/PSJira/Functions/Set-JiraIssueLink.ps1 b/PSJira/Functions/Set-JiraIssueLink.ps1 new file mode 100644 index 00000000..83c59428 --- /dev/null +++ b/PSJira/Functions/Set-JiraIssueLink.ps1 @@ -0,0 +1,88 @@ +function Set-JiraIssueLink +{ + <# + .Synopsis + .DESCRIPTION + .EXAMPLE + .EXAMPLE + .EXAMPLE + .INPUTS + .OUTPUTS + #> + [CmdletBinding(DefaultParameterSetName = 'ByInputObject')] + param( + # Issue key or PSJira.Issue object returned from Get-JiraIssue + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [Alias('Key')] + [Object[]] $Issue, + + [Parameter(Mandatory = $true)] + [Object[]] $IssueLink, + + [ValidateScript({Test-Path $_})] + [String] $ConfigFile, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential #, + + # [Switch] $PassThru + ) + + begin + { + Write-Debug "[Set-JiraIssue] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + Write-Debug "[Set-JiraIssue] Completed Begin block." + } + + process + { + foreach ($i in $Issue) + { + # $actOnIssueUri = $false + # $actOnAssigneeUri = $false + + Write-Debug "[Set-JiraIssue] Obtaining reference to issue" + $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential + foreach ($link in $IssueLink) + { + if ($link.inwardIssue) + { + $inwardIssue = New-Object -type PSObject -Prop @{key = $link.inwardIssue.key} + } else { + $inwardIssue = New-Object -type PSObject -Prop @{key = $issueObj.key} + } + + if ($link.outwardIssue) + { + $outwardIssue = New-Object -type PSObject -Prop @{key = $link.outwardIssue.key} + } else { + $outwardIssue = New-Object -type PSObject -Prop @{key = $issueObj.key} + } + + $body = New-Object -type PSObject -Prop @{ + type = New-Object -type PSObject -Prop @{name = $link.type.name} + inwardIssue = $inwardIssue + outwardIssue = $outwardIssue + } + $json = (ConvertTo-Json $body) + + $issueLinkURL = "$($server)/rest/api/latest/issueLink" + $issueResult = Invoke-JiraMethod -Method POST -URI $issueLinkURL -Body $json -Credential $Credential + } + + + + } + } + + end + { + Write-Debug "[Set-JiraIssue] Complete" + } +} \ No newline at end of file From bd0448387b0a40144c9ab98e994139b06f02b976 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 5 May 2016 15:47:45 +0200 Subject: [PATCH 004/102] fix of mandatory fields when creating an issue --- PSJira/Functions/New-JiraIssue.ps1 | 19 +++++++++++++++---- PSJira/Functions/Set-JiraConfigServer.ps1 | 13 ------------- PSJira/Functions/Set-JiraIssueLink.ps1 | 14 +------------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/PSJira/Functions/New-JiraIssue.ps1 b/PSJira/Functions/New-JiraIssue.ps1 index 7556c2ec..69335b18 100644 --- a/PSJira/Functions/New-JiraIssue.ps1 +++ b/PSJira/Functions/New-JiraIssue.ps1 @@ -36,7 +36,7 @@ function New-JiraIssue [Parameter(Mandatory = $true)] [String] $IssueType, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [Int] $Priority, [Parameter(Mandatory = $false)] @@ -51,6 +51,9 @@ function New-JiraIssue [Parameter(Mandatory = $false)] [String[]] $Labels, + [Parameter(Mandatory = $false)] + [Object] $Parent, + [Parameter(Mandatory = $false)] [Hashtable] $Fields, @@ -109,6 +112,11 @@ function New-JiraIssue Write-Debug "[New-JiraIssue] Reporter [$reporterStr] could not be accessed" throw "Unable to identify issue reporter. You must provide either the -Reporter parameter or the -Credential parameter, or the currently logged-on user must be a valid Jira user." } + + if ($Parent) + { + $Parent = Get-JiraIssue $Parent -Credential $Credential + } } process @@ -117,16 +125,19 @@ function New-JiraIssue $IssueTypeParam = New-Object -TypeName PSObject -Property @{"id"=[String] $IssueTypeObj.Id} $PriorityParam = New-Object -TypeName PSObject -Property @{"id"=[String] $Priority} $ReporterParam = New-Object -TypeName PSObject -Property @{"name"=$reporterObj.Name} + $ParentParam = New-Object -TypeName PSObject -Property @{"id"=$Parent.id} $props = @{ "project"=$ProjectParam; "summary"=$Summary; - "description"=$Description; "issuetype"=$IssueTypeParam; - "priority"=$PriorityParam; - "reporter"=$ReporterParam } + if ($Description) { $props["description"]=$Description } + if ($Priority) { $props["priority"]=$PriorityParam } + if ($Reporter) { $props["reporter"]=$ReporterParam } + if ($Parent) { $props["parent"]=$ParentParam } + if ($Labels) { [void] $props.Add('labels', $Labels) } diff --git a/PSJira/Functions/Set-JiraConfigServer.ps1 b/PSJira/Functions/Set-JiraConfigServer.ps1 index 3817f92d..1782db30 100644 --- a/PSJira/Functions/Set-JiraConfigServer.ps1 +++ b/PSJira/Functions/Set-JiraConfigServer.ps1 @@ -28,21 +28,8 @@ function Set-JiraConfigServer [String] $Server, [String] $ConfigFile - - [Parameter(Mandatory = $false)] - [PSCredential] $Credential ) - # Set default value for Parameter Credential for all commands in this Module - if ($Credential) - { - [System.Collections.ArrayList]$commandList = Get-Command -Noun Jira* | Where-Object {$_.Name -ne 'Set-JiraConfigServer'} - foreach ($cmd in $commandList) - { - $global:PSDefaultParameterValues["${cmd}:Credential"] = $Credential - } - } - # Using a default value for this parameter wouldn't handle all cases. We want to make sure # that the user can pass a $null value to the ConfigFile parameter...but if it's null, we # want to default to the script variable just as we would if the parameter was not diff --git a/PSJira/Functions/Set-JiraIssueLink.ps1 b/PSJira/Functions/Set-JiraIssueLink.ps1 index 83c59428..9b22f112 100644 --- a/PSJira/Functions/Set-JiraIssueLink.ps1 +++ b/PSJira/Functions/Set-JiraIssueLink.ps1 @@ -1,21 +1,9 @@ function Set-JiraIssueLink { - <# - .Synopsis - .DESCRIPTION - .EXAMPLE - .EXAMPLE - .EXAMPLE - .INPUTS - .OUTPUTS - #> [CmdletBinding(DefaultParameterSetName = 'ByInputObject')] param( # Issue key or PSJira.Issue object returned from Get-JiraIssue - [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias('Key')] [Object[]] $Issue, From ab8f0d818a032a067fce9f221102b80d2378c7ac Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 6 May 2016 20:55:54 +0200 Subject: [PATCH 005/102] improvements --- PSJira/Functions/Internal/ConvertTo-JiraIssue.ps1 | 2 +- PSJira/Functions/New-JiraIssue.ps1 | 4 +++- PSJira/Functions/Set-JiraIssueLabel.ps1 | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/PSJira/Functions/Internal/ConvertTo-JiraIssue.ps1 b/PSJira/Functions/Internal/ConvertTo-JiraIssue.ps1 index 02a56b11..7470dbfe 100644 --- a/PSJira/Functions/Internal/ConvertTo-JiraIssue.ps1 +++ b/PSJira/Functions/Internal/ConvertTo-JiraIssue.ps1 @@ -120,7 +120,7 @@ function ConvertTo-JiraIssue } } -# Write-Debug "[ConvertTo-JiraIssue] Checking for any additional fields" + Write-Debug "[ConvertTo-JiraIssue] Checking for any additional fields" $extraFields = $i.fields.PSObject.Properties | Where-Object -FilterScript { $_.Name -notin $props.Keys } foreach ($f in $extraFields) { diff --git a/PSJira/Functions/New-JiraIssue.ps1 b/PSJira/Functions/New-JiraIssue.ps1 index 69335b18..54781c51 100644 --- a/PSJira/Functions/New-JiraIssue.ps1 +++ b/PSJira/Functions/New-JiraIssue.ps1 @@ -113,8 +113,10 @@ function New-JiraIssue throw "Unable to identify issue reporter. You must provide either the -Reporter parameter or the -Credential parameter, or the currently logged-on user must be a valid Jira user." } - if ($Parent) + if ($Parent.key) { + $Parent = Get-JiraIssue $Parent.key -Credential $Credential + } elseif ($Parent) { $Parent = Get-JiraIssue $Parent -Credential $Credential } } diff --git a/PSJira/Functions/Set-JiraIssueLabel.ps1 b/PSJira/Functions/Set-JiraIssueLabel.ps1 index 2d5aef27..98cf92ec 100644 --- a/PSJira/Functions/Set-JiraIssueLabel.ps1 +++ b/PSJira/Functions/Set-JiraIssueLabel.ps1 @@ -112,7 +112,7 @@ # extra $null being added to the array, so we need to # account for that in the Where-Object as well as the # Remove parameter. - $newLabels = $currentLabels + $Add | Where-Object -FilterScript {$_ -ne $null -and $Remove -notcontains $_} + $newLabels = $currentLabels + $Add | Where-Object -FilterScript {$_ -ne $null -and $Remove -notcontains $_ -and $currentLabels -notcontains $_} } if ($isDirty) From 8734ab0b3f02e920b7379b95e100ab1ebbe41cde Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 22 Jun 2016 15:29:06 +0200 Subject: [PATCH 006/102] trap cases where API returns void --- PSJira/Functions/Internal/Invoke-JiraMethod.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PSJira/Functions/Internal/Invoke-JiraMethod.ps1 b/PSJira/Functions/Internal/Invoke-JiraMethod.ps1 index 1c5d9dcc..98e28c22 100644 --- a/PSJira/Functions/Internal/Invoke-JiraMethod.ps1 +++ b/PSJira/Functions/Internal/Invoke-JiraMethod.ps1 @@ -90,7 +90,9 @@ function Invoke-JiraMethod Write-Debug "[Invoke-JiraMethod] Retrieved body of HTTP response for more information about the error (`$body)" $result = ConvertFrom-Json2 -InputObject $body } else { - $result = ConvertFrom-Json2 -InputObject $webResponse.Content + try { + $result = ConvertFrom-Json2 -InputObject $webResponse.Content + } catch {} } if ($result.errors -ne $null) From 72bb1b978f8a756a6a330644a99af68a2ee6be1a Mon Sep 17 00:00:00 2001 From: Joshua T Date: Thu, 1 Sep 2016 21:33:39 -0500 Subject: [PATCH 007/102] Created helper function for link types --- .../ConvertTo-JiraIssueLinkType.Tests.ps1 | 82 +++++++++++++++++++ .../Internal/ConvertTo-JiraIssueLinkType.ps1 | 26 ++++++ 2 files changed, 108 insertions(+) create mode 100644 PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 create mode 100644 PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 new file mode 100644 index 00000000..c8e4359f --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 @@ -0,0 +1,82 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + Describe "ConvertTo-JiraIssueLinkType" { + function defProp($obj, $propName, $propValue) + { + It "Defines the '$propName' property" { + $obj.$propName | Should Be $propValue + } + } + + $sampleJson = @' +{ + "issueLinkTypes": [ + { + "id": "10000", + "name": "Blocks", + "inward": "is blocked by", + "outward": "blocks", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10000" + }, + { + "id": "10001", + "name": "Cloners", + "inward": "is cloned by", + "outward": "clones", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10001" + }, + { + "id": "10002", + "name": "Duplicate", + "inward": "is duplicated by", + "outward": "duplicates", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10002" + }, + { + "id": "10003", + "name": "Relates", + "inward": "relates to", + "outward": "relates to", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10003" + } + ] +} +'@ + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson | + Select-Object -ExpandProperty issueLinkTypes + + Context 'Behavior testing' { + $r = ConvertTo-JiraIssueLinkType -InputObject $sampleObject[0] + It "Provides output" { + $r | Should Not BeNullOrEmpty + } + + It "Sets the type name to PSJira.issueLinkType" { + ($r | Get-Member).TypeName | Should Be 'PSJira.issueLinkType' + } + + defProp $r 'Id' '10000' + defProp $r 'Name' 'Blocks' + defProp $r 'InwardText' 'is blocked by' + defProp $r 'OutwardText' 'blocks' + defProp $r 'RestUrl' 'http://jira.example.com/rest/api/latest/issueLinkType/10000' + + It "Provides an array of objects if an array is passed" { + $r2 = ConvertTo-JiraIssueLinkType -InputObject $sampleObject + $r2.Count | Should Be 4 + $r2[0].Id | Should Be '10000' + $r2[1].Id | Should Be '10001' + $r2[2].Id | Should Be '10002' + $r2[3].Id | Should Be '10003' + } + + It "Handles pipeline input" { + $r = $sampleObject | ConvertTo-JiraIssueLinkType + $r.Count | Should Be 4 + } + } + } +} diff --git a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 new file mode 100644 index 00000000..316d97ac --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 @@ -0,0 +1,26 @@ +function ConvertTo-JiraIssueLinkType { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject + ) + + process + { + foreach ($i in $InputObject) + { + $obj = [PSCustomObject] @{ + PSTypeName = 'PSJira.IssueLinkType' + Id = $i.id; + Name = $i.name; + InwardText = $i.inward; + OutwardText = $i.outward; + RestUrl = $i.self; + } + + Write-Output $obj + } + } +} From 75ba2d623c2184811df73b205c8743266dd5636a Mon Sep 17 00:00:00 2001 From: Joshua T Date: Thu, 1 Sep 2016 21:51:03 -0500 Subject: [PATCH 008/102] Created function Get-JiraIssueLinkType --- PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 | 132 ++++++++++++++++++ PSJira/Public/Get-JiraIssueLinkType.ps1 | 98 +++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 create mode 100644 PSJira/Public/Get-JiraIssueLinkType.ps1 diff --git a/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 b/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 new file mode 100644 index 00000000..9e7b7109 --- /dev/null +++ b/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 @@ -0,0 +1,132 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + $ShowMockData = $true + $ShowDebugText = $true + + Describe 'Get-JiraIssueLinkType' { + Mock Get-JiraConfigServer { 'https://jira.example.com' } + + if ($ShowDebugText) + { + Mock 'Write-Debug' { + Write-Host "[DEBUG] $Message" -ForegroundColor Yellow + } + } + + function ShowMockInfo($functionName, [String[]] $params) { + if ($ShowMockData) + { + Write-Host " Mocked $functionName" -ForegroundColor Cyan + foreach ($p in $params) { + Write-Host " [$p] $(Get-Variable -Name $p -ValueOnly)" -ForegroundColor Cyan + } + } + } + + Context "Sanity checking" { + $command = Get-Command -Name Get-JiraIssueLinkType + + function defParam($name) + { + It "Has a -$name parameter" { + $command.Parameters.Item($name) | Should Not BeNullOrEmpty + } + } + + defParam 'LinkType' + defParam 'Credential' + } + + $filterAll = {$Method -eq 'Get' -and $Uri -ceq 'https://jira.example.com/rest/api/latest/issueLinkType'} + $filterOne = {$Method -eq 'Get' -and $Uri -ceq 'https://jira.example.com/rest/api/latest/issueLinkType/10000'} + + Mock Invoke-JiraMethod -ParameterFilter $filterAll { + ShowMockInfo 'Invoke-JiraMethod' 'Method','Uri' + [PSCustomObject] @{ + issueLinkTypes = @( + # We don't care what data actually comes back here + 'foo' + ) + } + } + + Mock Invoke-JiraMethod -ParameterFilter $filterOne { + ShowMockInfo 'Invoke-JiraMethod' 'Method','Uri' + [PSCustomObject] @{ + issueLinkTypes = @( + 'bar' + ) + } + } + + Mock Invoke-JiraMethod { + ShowMockInfo 'Invoke-JiraMethod' 'Method','Uri' + throw "Unhandled call to Invoke-JiraMethod" + } + + Context "Behavior testing - returning all link types" { + + Mock ConvertTo-JiraIssueLinkType { + ShowMockInfo 'ConvertTo-JiraIssueLinkType' + + # We also don't care what comes out of here - this function has its own tests + [PSCustomObject] @{ + PSTypeName = 'PSJira.IssueLinkType' + foo = 'bar' + } + } + + $output = Get-JiraIssueLinkType + + It 'Uses Invoke-JiraMethod to communicate with JIRA' { + Assert-MockCalled -CommandName Invoke-JiraMethod -ParameterFilter $filterAll -Exactly -Times 1 -Scope Context + } + + It 'Returns all link types if no value is passed to the -LinkType parameter' { + $output | Should Not BeNullOrEmpty + } + + It 'Uses the helper method ConvertTo-JiraIssueLinkType to process output' { + Assert-MockCalled -CommandName ConvertTo-JiraIssueLinkType -ParameterFilter {$InputObject -contains 'foo'} -Exactly -Times 1 -Scope Context + } + + It 'Outputs PSJira.IssueLinkType objects' { + $output | Should Not BeNullOrEmpty + ($output | Get-Member).TypeName | Should Be 'PSJira.IssueLinkType' + $output.foo | Should Be 'bar' + } + } + + Context "Behavior testing - returning one link type" { + Mock ConvertTo-JiraIssueLinkType { + ShowMockInfo 'ConvertTo-JiraIssueLinkType' + + # We also don't care what comes out of here - this function has its own tests + [PSCustomObject] @{ + PSTypeName = 'PSJira.IssueLinkType' + Name = 'myLink' + ID = 5 + } + } + + It 'Returns a single link type if an ID number is passed to the -LinkType parameter' { + $output = Get-JiraIssueLinkType -LinkType 10000 + Assert-MockCalled -CommandName Invoke-JiraMethod -ParameterFilter $filterOne -Exactly -Times 1 -Scope It + $output | Should Not BeNullOrEmpty + @($output).Count | Should Be 1 + } + + It 'Returns the correct link type it a type name is passed to the -LinkType parameter' { + $output = Get-JiraIssueLinkType -LinkType 'myLink' + Assert-MockCalled -CommandName Invoke-JiraMethod -ParameterFilter $filterAll -Exactly -Times 1 -Scope It + $output | Should Not BeNullOrEmpty + @($output).Count | Should Be 1 + $output.ID | Should Be 5 + } + } + } +} diff --git a/PSJira/Public/Get-JiraIssueLinkType.ps1 b/PSJira/Public/Get-JiraIssueLinkType.ps1 new file mode 100644 index 00000000..b7df4674 --- /dev/null +++ b/PSJira/Public/Get-JiraIssueLinkType.ps1 @@ -0,0 +1,98 @@ +function Get-JiraIssueLinkType +{ + <# + .SYNOPSIS + Gets available issue link types + .DESCRIPTION + This function gets available issue link types from a JIRA server. It can also return specific information about a single issue link type. + + This is a useful function for discovering data about issue link types in order to create and modify issue links on issues. + .EXAMPLE + C:\PS> Get-JiraIssueLinkType + This example returns all available links fron the JIRA server + .EXAMPLE + C:\PS> Get-JiraIssueLinkType -LinkType 1 + This example returns information about the link type with ID 1. + .INPUTS + This function does not accept pipeline input. + .OUTPUTS + This function outputs the PSJira.IssueLinkType object(s) that represent the JIRA issue link type(s). + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> + [CmdletBinding()] + param( + # The Issue Type name or ID to search + [Parameter(Mandatory = $false, + Position = 0, + ValueFromRemainingArguments = $true)] + [Object] $LinkType, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin + { + Write-Debug "[Get-JiraIssueLinkType] Reading server from config file" + try + { + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + } catch { + $err = $_ + Write-Debug "[Get-JiraIssueLinkType] Encountered an error reading the Jira server." + throw $err + } + + $uri = "$server/rest/api/latest/issueLinkType" + } + + process + { + $searchLinks = $false + if ($LinkType) + { + # If the link type provided is an int, we can assume it's an ID number. + # If it's a String, it's probably a name, though, and there isn't an API call to look up a link type by name. + if ($LinkType -is [int]) + { + Write-Debug "[Get-JiraIssueLinkType] Link type ID was specified; obtaining issue link type $LinkType" + $uri = "$uri/$LinkType" + } else { + Write-Debug "[Get-JiraIssueLinkType] Assuming -LinkType parameter $LinkType to be a name; obtaining all link types" + $searchLinks = $true + } + } else { + Write-Debug "[Get-JiraIssueLinkType] Obtaining all issue link types from Jira" + } + + $jiraResult = Invoke-JiraMethod -Method Get -URI $uri -Credential $Credential + + if ($jiraResult -and $jiraResult.issueLinkTypes) + { + Write-Debug "[Get-JiraIssueLinkType] Converting Jira output to custom object" + $obj = ConvertTo-JiraIssueLinkType -InputObject $jiraResult.issueLinkTypes + + if ($searchLinks) + { + Write-Debug "[Get-JiraIssueLinkType] Searching for link type with name [$LinkType]" + $output = $obj | Where-Object {$_.Name -eq $LinkType} + if ($output) + { + Write-Debug "[Get-JiraIssueLinkType] Found issue with ID [$($output.ID)]" + } else { + Write-Debug "[Get-JiraIssueLinkType] Could not find an issue." + Write-Verbose "Unable to identify issue link type $LinkType." + } + } else { + $output = $obj + } + + Write-Debug "[Get-JiraIssueLinkType] Writing output" + Write-Output $obj + } else { + Write-Debug "[Get-JiraIssueLinkType] No issue link types were found." + } + } +} From 06aead86d4ec5d00e6fce65e49b2299b565e9576 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Thu, 1 Sep 2016 21:51:30 -0500 Subject: [PATCH 009/102] Added Get-JiraIssueLinkType to function list --- PSJira/PSJira.psd1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index fa968ad6..e8b88c65 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -69,15 +69,15 @@ FormatsToProcess = 'PSJira.format.ps1xml' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira', - 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', - 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', - 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', - 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', - 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', - 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', - 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', - 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', +FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira', + 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', + 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', + 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', + 'Get-JiraIssueLinkType', 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', + 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', + 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', + 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', + 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', 'Set-JiraIssueLabel', 'Set-JiraUser' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. @@ -122,7 +122,7 @@ PrivateData = @{ # ExternalModuleDependencies = '' } # End of PSData hashtable - + } # End of PrivateData hashtable # HelpInfo URI of this module From 723c49e46926e810f2898a432c3724333ab8f6c7 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Thu, 1 Sep 2016 21:52:37 -0500 Subject: [PATCH 010/102] Disabled debug output --- PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 b/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 index 9e7b7109..b9631345 100644 --- a/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 +++ b/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 @@ -4,8 +4,8 @@ $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") InModuleScope PSJira { - $ShowMockData = $true - $ShowDebugText = $true + $ShowMockData = $false + $ShowDebugText = $false Describe 'Get-JiraIssueLinkType' { Mock Get-JiraConfigServer { 'https://jira.example.com' } From 9de585a22fb4f82057eca229b08f23545999429b Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 16 Dec 2016 13:32:35 +0100 Subject: [PATCH 011/102] added functino to Get-JiraRemoteLink --- PSJira/PSJira.psd1 | 6 +-- PSJira/Public/Get-JiraRemoteLink.ps1 | 55 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 PSJira/Public/Get-JiraRemoteLink.ps1 diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index 1777ba8f..cfbfcd64 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -73,11 +73,11 @@ FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira' 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', - 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', + 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', 'Remove-JiraRemoteLink', 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', - 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', - 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', + 'Remove-JiraGroup', 'Remove-JiraGroupMember', + 'Remove-JiraSession', 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', 'Set-JiraIssueLabel', 'Set-JiraUser' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 new file mode 100644 index 00000000..186d3e51 --- /dev/null +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -0,0 +1,55 @@ +function Get-JiraRemoteLink +{ + #https://docs.atlassian.com/jira/REST/latest/#d2e928 + #Get-JiraRemoteLink -apiURi $JiraRestURi -cred $cred -issueID "HCF-966" + #Get-JiraRemoteLink -apiURi $JiraRestURi -cred $cred -issueID "HCF-120" + [CmdletBinding()] + param( + [Parameter(ValueFromPipelineByPropertyName = $true, + ParameterSetName = 'ByIssueKey', + ValueFromPipeline = $true, + Mandatory = $true, + Position = 0 + )] + [ValidateNotNullOrEmpty()] + [String[]]$Key, + + # Get a single link by it's id + [int]$linkId, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + Begin + { + Write-Debug "[Get-JiraRemoteLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + } + + Process + { + foreach ($k in $key) + { + Write-Debug "[Get-JiraIssue] Processing issue key [$k]" + $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink" + if ($linkId) + { $issueURL += "/$linkId" } + + Write-Debug "[Get-JiraIssue] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential + + if ($result) + { + Write-Debug "[Get-JiraIssue] Converting REST result to Jira object" + ConvertFrom-Json $result + } + } + } + + End + { + Write-Debug "[Get-JiraIssue] Complete" + } +} From ca32b97bec3ffe3d4564088e5f8e06d0a110c632 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 16 Dec 2016 13:32:56 +0100 Subject: [PATCH 012/102] added function to Remove-JiraRemoteLink --- PSJira/PSJira.psd1 | 2 +- PSJira/Public/Remove-JiraRemoteLink.ps1 | 66 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 PSJira/Public/Remove-JiraRemoteLink.ps1 diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index cfbfcd64..d307a865 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -76,7 +76,7 @@ FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira' 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', 'Remove-JiraRemoteLink', 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', - 'Remove-JiraGroup', 'Remove-JiraGroupMember', + 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraRemoteLink', 'Remove-JiraSession', 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', 'Set-JiraIssueLabel', 'Set-JiraUser' diff --git a/PSJira/Public/Remove-JiraRemoteLink.ps1 b/PSJira/Public/Remove-JiraRemoteLink.ps1 new file mode 100644 index 00000000..6f9470a3 --- /dev/null +++ b/PSJira/Public/Remove-JiraRemoteLink.ps1 @@ -0,0 +1,66 @@ +function Remove-JiraRemoteLink +{ + #https://docs.atlassian.com/jira/REST/latest/#d2e928 + [CmdletBinding()] + param( + [Parameter(ValueFromPipelineByPropertyName = $true, + ParameterSetName = 'ByIssueKey', + ValueFromPipeline = $true, + Mandatory = $true, + Position = 0 + )] + [ValidateNotNullOrEmpty()] + [String[]]$Key, + + [Parameter(Mandatory = $true)] + [string]$GlobalId, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + Begin + { + Write-Debug "[Get-JiraRemoteLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + + + if ($apiURi -notmatch "\/$") + { $apiURi = $apiURi + "/" } + $restAPI = "${apiURi}rest/api/2/issue" + + $header = @{ + Authorization = "Basic $([System.Convert]::ToBase64String( + [System.Text.Encoding]::UTF8.GetBytes( + ($Credential.UserName)+":"+($Credential.getnetworkcredential().password) + ) + ))" + "Content-Type" = "application/json" + } + } + + Process + { + + foreach ($k in $key) + { + Write-Debug "[Get-JiraIssue] Processing issue key [$k]" + $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink" + + $body = "{globalId: `"$GlobalId`"}" + + Write-Debug "[Get-JiraIssue] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Delete -URI -Body $body $issueURL -Credential $Credential + + if ($result) + { + Write-Debug "[Get-JiraIssue] Converting REST result to Jira object" + ConvertFrom-Json $result + } + } + } + + End {} +} From 0091c86cfc0753f7ece3f9bf0e70a70b4d474681 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 16 Dec 2016 13:48:12 +0100 Subject: [PATCH 013/102] [fixed] misplaced conversion to object --- PSJira/Public/Get-JiraRemoteLink.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 index 186d3e51..d20742cf 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -42,8 +42,7 @@ function Get-JiraRemoteLink if ($result) { - Write-Debug "[Get-JiraIssue] Converting REST result to Jira object" - ConvertFrom-Json $result + $result } } } From c5cd692022ac69e30a1999801c94fd5e2173bf8e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 16 Dec 2016 13:48:38 +0100 Subject: [PATCH 014/102] [fixed] copy/paste error in function name --- PSJira/PSJira.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index d307a865..477580a0 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -73,7 +73,7 @@ FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira' 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', - 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', 'Remove-JiraRemoteLink', + 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', 'Get-JiraRemoteLink', 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraRemoteLink', From c340c80e4a65d0ca3a2d23f7097a30a3aff5ecfd Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 16 Dec 2016 15:20:06 +0100 Subject: [PATCH 015/102] function can return Invoke-JiraMethod --- PSJira/Public/Get-JiraRemoteLink.ps1 | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 index d20742cf..70bf8549 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -32,23 +32,18 @@ function Get-JiraRemoteLink { foreach ($k in $key) { - Write-Debug "[Get-JiraIssue] Processing issue key [$k]" + Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink" if ($linkId) { $issueURL += "/$linkId" } - Write-Debug "[Get-JiraIssue] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential - - if ($result) - { - $result - } + Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" + Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential } } End { - Write-Debug "[Get-JiraIssue] Complete" + Write-Debug "[Get-JiraRemoteLink] Complete" } } From c79e51a8757a24ae507b1f3ef93d38acec2b7e04 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 16 Dec 2016 15:20:46 +0100 Subject: [PATCH 016/102] [fixed] switched to `id` instead of `globalId` --- PSJira/Public/Remove-JiraRemoteLink.ps1 | 38 ++++++------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/PSJira/Public/Remove-JiraRemoteLink.ps1 b/PSJira/Public/Remove-JiraRemoteLink.ps1 index 6f9470a3..4b73dde2 100644 --- a/PSJira/Public/Remove-JiraRemoteLink.ps1 +++ b/PSJira/Public/Remove-JiraRemoteLink.ps1 @@ -13,7 +13,7 @@ function Remove-JiraRemoteLink [String[]]$Key, [Parameter(Mandatory = $true)] - [string]$GlobalId, + [string]$LinkId, # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] @@ -24,21 +24,6 @@ function Remove-JiraRemoteLink { Write-Debug "[Get-JiraRemoteLink] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - - - - if ($apiURi -notmatch "\/$") - { $apiURi = $apiURi + "/" } - $restAPI = "${apiURi}rest/api/2/issue" - - $header = @{ - Authorization = "Basic $([System.Convert]::ToBase64String( - [System.Text.Encoding]::UTF8.GetBytes( - ($Credential.UserName)+":"+($Credential.getnetworkcredential().password) - ) - ))" - "Content-Type" = "application/json" - } } Process @@ -46,21 +31,16 @@ function Remove-JiraRemoteLink foreach ($k in $key) { - Write-Debug "[Get-JiraIssue] Processing issue key [$k]" - $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink" + Write-Debug "[Remove-JiraRemoteLink] Processing issue key [$k]" + $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink/${linkId}" - $body = "{globalId: `"$GlobalId`"}" - - Write-Debug "[Get-JiraIssue] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Delete -URI -Body $body $issueURL -Credential $Credential - - if ($result) - { - Write-Debug "[Get-JiraIssue] Converting REST result to Jira object" - ConvertFrom-Json $result - } + Write-Debug "[Remove-JiraRemoteLink] Preparing for blastoff!" + Invoke-JiraMethod -Method Delete -URI $issueURL -Credential $Credential } } - End {} + End + { + Write-Debug "[Remove-JiraRemoteLink] Complete" + } } From ba55220e71bc7f14a3eeee9c730b5aed6aee60e9 Mon Sep 17 00:00:00 2001 From: Eugene Bekker Date: Tue, 24 Jan 2017 15:59:24 -0500 Subject: [PATCH 017/102] Adds support for listing and managing issue watchers --- PSJira/PSJira.psd1 | 6 +- PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 | 74 +++++++++++++ PSJira/Public/Add-JiraIssueWatcher.ps1 | 96 +++++++++++++++++ PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 | 102 ++++++++++++++++++ PSJira/Public/Get-JiraIssueWatchers.ps1 | 76 +++++++++++++ PSJira/Public/Remove-JiraIssueWatcher.ps1 | 94 ++++++++++++++++ 6 files changed, 445 insertions(+), 3 deletions(-) create mode 100644 PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 create mode 100644 PSJira/Public/Add-JiraIssueWatcher.ps1 create mode 100644 PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 create mode 100644 PSJira/Public/Get-JiraIssueWatchers.ps1 create mode 100644 PSJira/Public/Remove-JiraIssueWatcher.ps1 diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index 1252b564..86077daa 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -69,14 +69,14 @@ FormatsToProcess = 'PSJira.format.ps1xml' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Get-JiraComponent', 'Format-Jira', +FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Add-JiraIssueWatcher', 'Get-JiraComponent', 'Format-Jira', 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', - 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', + 'Get-JiraIssueComment', 'Get-JiraIssueWatchers', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', - 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', + 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', 'Remove-JiraIssueWatcher', 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', 'Set-JiraIssueLabel', 'Set-JiraUser' diff --git a/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 b/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 new file mode 100644 index 00000000..26a9d86b --- /dev/null +++ b/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 @@ -0,0 +1,74 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + $ShowMockData = $false + + $jiraServer = 'http://jiraserver.example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + + Describe "Add-JiraIssueWatcher" { + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue -ModuleName PSJira { + [PSCustomObject] @{ + ID = $issueID; + Key = $issueKey; + RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; + } + } + + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watcher"} { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + Write-Host " [URI] $URI" -ForegroundColor Cyan + } + + # This data was created from a GUI REST client, then sanitized. A lot of extra data was also removed to save space. + # Many Bothans died to bring us this information. + ConvertFrom-Json2 $restResponse + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed + Write-Host " [Method] $Method" -ForegroundColor DarkRed + Write-Host " [URI] $URI" -ForegroundColor DarkRed + throw "Unidentified call to Invoke-JiraMethod" + } + + ############# + # Tests + ############# + + It "Adds a Watcher to an issue in JIRA" { + $WatcherResult = Add-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey + $WatcherResult | Should Not BeNullOrEmpty + + # Get-JiraIssue should be used to identiyf the issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + + # Invoke-JiraMethod should be used to add the Watcher + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Accepts pipeline input from Get-JiraIssue" { + $WatcherResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWatcher -Watcher 'fred' + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + } +} + + diff --git a/PSJira/Public/Add-JiraIssueWatcher.ps1 b/PSJira/Public/Add-JiraIssueWatcher.ps1 new file mode 100644 index 00000000..15047b04 --- /dev/null +++ b/PSJira/Public/Add-JiraIssueWatcher.ps1 @@ -0,0 +1,96 @@ +function Add-JiraIssueWatcher +{ + <# + .Synopsis + Adds a watcher to an existing JIRA issue + .DESCRIPTION + This function adds a watcher to an existing issue in JIRA. + .EXAMPLE + Add-JiraIssueWatcher -Watcher "fred" -Issue "TEST-001" + This example adds a watcher to the issue TEST-001. + .EXAMPLE + Get-JiraIssue "TEST-002" | Add-JiraIssueWatcher "fred" + This example illustrates pipeline use from Get-JiraIssue to Add-JiraIssueWatcher. + .EXAMPLE + Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Add-JiraIssueWatcher "fred" } + This example illustrates adding watcher on all projects which match a given JQL query. It would be best to validate the query first to make sure the query returns the expected issues! + .INPUTS + This function can accept PSJira.Issue objects via pipeline. + .OUTPUTS + This function does not provide output. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> + [CmdletBinding()] + param( + # Watcher that should be added to JIRA + [Parameter(Mandatory = $true, + Position = 0)] + [string[]] $Watcher, + + # Issue that should be watched + [Parameter(Mandatory = $true, + Position = 1, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [Alias('Key')] + [Object] $Issue, + + # Credentials to use to connect to Jira. If not specified, this function will use + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin + { + Write-Debug "[Add-JiraIssueWatcher] Begin" + # We can't validate pipeline input here, since pipeline input doesn't exist in the Begin block. + } + + process + { +# Write-Debug "[Add-JiraIssueWatcher] Checking Issue parameter" +# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') +# { +# Write-Debug "[Add-JiraIssueWatcher] Issue parameter is a PSJira.Issue object" +# $issueObj = $Issue +# } else { +# $issueKey = $Issue.ToString() +# Write-Debug "[Add-JiraIssueWatcher] Issue key is assumed to be [$issueKey] via ToString()" +# Write-Verbose "Searching for issue [$issueKey]" +# try +# { +# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential +# } catch { +# $err = $_ +# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' +# throw $err +# } +# } +# +# if (-not $issueObj) +# { +# Write-Debug "[Add-JiraIssueWatcher] No Jira issues were found for parameter [$Issue]. An exception will be thrown." +# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" +# } + + Write-Debug "[Add-JiraIssueWatcher] Obtaining a reference to Jira issue [$Issue]" + $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential + + $url = "$($issueObj.RestURL)/watchers" + + foreach ($w in $Watcher) { + $body = """$w""" + + Write-Debug "[Add-JiraIssueWatcher] Preparing for blastoff!" + $rawResult = Invoke-JiraMethod -Method Post -URI $url -Body $body -Credential $Credential + } + } + + end + { + Write-Debug "[Add-JiraIssueWatcher] Complete" + } +} + + diff --git a/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 b/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 new file mode 100644 index 00000000..ffe568b0 --- /dev/null +++ b/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 @@ -0,0 +1,102 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + Describe "Get-JiraIssueWatchers" { + + $ShowMockData = $false + + $jiraServer = 'http://jiraserver.example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + + ## Sample straight from the API: + ## https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssueWatchers + $restResult = @" +{ + "self": "http://www.example.com/jira/rest/api/2/issue/EX-1/watchers", + "isWatching": false, + "watchCount": 1, + "watchers": [ + { + "self": "http://www.example.com/jira/rest/api/2/user?username=fred", + "name": "fred", + "displayName": "Fred F. User", + "active": false + } + ] +} +"@ + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue -ModuleName PSJira { + [PSCustomObject] @{ + ID = $issueID; + Key = $issueKey; + RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; + } + } + + # Obtaining watchers from an issue...this is IT-3676 in the test environment + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-JiraMethod with GET method" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + Write-Host " [URI] $URI" -ForegroundColor Cyan + } + ConvertFrom-Json2 -InputObject $restResult + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed + Write-Host " [Method] $Method" -ForegroundColor DarkRed + Write-Host " [URI] $URI" -ForegroundColor DarkRed + throw "Unidentified call to Invoke-JiraMethod" + } + +# Mock Write-Debug { +# Write-Host "DEBUG: $Message" -ForegroundColor Yellow +# } + + ############# + # Tests + ############# + + It "Obtains all Jira watchers from a Jira issue if the issue key is provided" { + $watchers = Get-JiraIssueWatchers -Issue $issueKey + $watchers | Should Not BeNullOrEmpty + @($watchers).Count | Should Be 1 + $watchers.name | Should Be "fred" + $watchers.self | Should Be "$jiraServer/rest/api/2/user?username=fred" + + # Get-JiraIssue should be called to identify the -Issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + + # Normally, this would be called once in Get-JiraIssue and a second time in Get-JiraIssueWatchers, but + # since we've mocked Get-JiraIssue out, it will only be called once. + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Obtains all Jira watchers from a Jira issue if the Jira object is provided" { + $issue = Get-JiraIssue -Key $issueKey + $watchers = Get-JiraIssueWatchers -Issue $issue + $watchers | Should Not BeNullOrEmpty + $watchers.name | Should Be "fred" + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Handles pipeline input from Get-JiraIssue" { + $watchers = Get-JiraIssue -Key $issueKey | Get-JiraIssueWatchers + $watchers | Should Not BeNullOrEmpty + $watchers.name | Should Be "fred" + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + } +} + + diff --git a/PSJira/Public/Get-JiraIssueWatchers.ps1 b/PSJira/Public/Get-JiraIssueWatchers.ps1 new file mode 100644 index 00000000..e6c46536 --- /dev/null +++ b/PSJira/Public/Get-JiraIssueWatchers.ps1 @@ -0,0 +1,76 @@ +function Get-JiraIssueWatchers +{ + <# + .Synopsis + Returns watchers on an issue in JIRA. + .DESCRIPTION + This function obtains watchers from existing issues in JIRA. + .EXAMPLE + Get-JiraIssueWatchers -Key TEST-001 + This example returns all watchers posted to issue TEST-001. + .EXAMPLE + Get-JiraIssue TEST-002 | Get-JiraIssueWatchers + This example illustrates use of the pipeline to return all watchers on issue TEST-002. + .INPUTS + This function can accept PSJira.Issue objects, Strings, or Objects via the pipeline. It uses Get-JiraIssue to identify the issue parameter; see its Inputs section for details on how this function handles inputs. + .OUTPUTS + This function outputs all PSJira.Watchers issues associated with the provided issue. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> + [CmdletBinding()] + param( + # JIRA issue to check for watchers. Can be a PSJira.Issue object, issue key, or internal issue ID. + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [Alias('Key')] + [Object] $Issue, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin + { + # We can't validate pipeline input here, since pipeline input doesn't exist in the Begin block. + } + + process + { + Write-Debug "Obtaining a reference to Jira issue [$Issue]" + $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential + + $url = "$($issueObj.RestURL)/watchers" + + Write-Debug "Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Get -URI $url -Credential $Credential + + if ($result) + { + if ($result.watchers) + { + Write-Verbose "Result: $($result)" + Write-Verbose "Watchers: $($result.Watchers)" + + Write-Debug "Converting result to Jira user objects" + $obj = ConvertTo-JiraUser -InputObject $result.watchers + + Write-Debug "Outputting results" + Write-Output $obj + } else { + Write-Debug "Result appears to be in an unexpected format. Outputting raw result." + Write-Output $result + } + } else { + Write-Debug "Invoke-JiraMethod returned no results to output." + } + } + + end + { + Write-Debug "Completed Get-JiraIssueWatchers" + } +} diff --git a/PSJira/Public/Remove-JiraIssueWatcher.ps1 b/PSJira/Public/Remove-JiraIssueWatcher.ps1 new file mode 100644 index 00000000..04d27ac6 --- /dev/null +++ b/PSJira/Public/Remove-JiraIssueWatcher.ps1 @@ -0,0 +1,94 @@ +function Remove-JiraIssueWatcher +{ + <# + .Synopsis + Removes a watcher from an existing JIRA issue + .DESCRIPTION + This function removes a watcher from an existing issue in JIRA. + .EXAMPLE + Remove-JiraIssueWatcher -Watcher "fred" -Issue "TEST-001" + This example removes a watcher from the issue TEST-001. + .EXAMPLE + Get-JiraIssue "TEST-002" | Remove-JiraIssueWatcher "fred" + This example illustrates pipeline use from Get-JiraIssue to Remove-JiraIssueWatcher. + .EXAMPLE + Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Remove-JiraIssueWatcher "fred" } + This example illustrates removing watcher on all projects which match a given JQL query. It would be best to validate the query first to make sure the query returns the expected issues! + .INPUTS + This function can accept PSJira.Issue objects via pipeline. + .OUTPUTS + This function does not provide output. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> + [CmdletBinding()] + param( + # Watcher that should be removed from JIRA + [Parameter(Mandatory = $true, + Position = 0)] + [string[]] $Watcher, + + # Issue that should be updated + [Parameter(Mandatory = $true, + Position = 1, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [Alias('Key')] + [Object] $Issue, + + # Credentials to use to connect to Jira. If not specified, this function will use + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin + { + Write-Debug "[Remove-JiraIssueWatcher] Begin" + # We can't validate pipeline input here, since pipeline input doesn't exist in the Begin block. + } + + process + { +# Write-Debug "[Remove-JiraIssueWatcher] Checking Issue parameter" +# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') +# { +# Write-Debug "[Remove-JiraIssueWatcher] Issue parameter is a PSJira.Issue object" +# $issueObj = $Issue +# } else { +# $issueKey = $Issue.ToString() +# Write-Debug "[Remove-JiraIssueWatcher] Issue key is assumed to be [$issueKey] via ToString()" +# Write-Verbose "Searching for issue [$issueKey]" +# try +# { +# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential +# } catch { +# $err = $_ +# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' +# throw $err +# } +# } +# +# if (-not $issueObj) +# { +# Write-Debug "[Remove-JiraIssueWatcher] No Jira issues were found for parameter [$Issue]. An exception will be thrown." +# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" +# } + + Write-Debug "[Remove-JiraIssueWatcher] Obtaining a reference to Jira issue [$Issue]" + $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential + + foreach ($w in $Watcher) { + $url = "$($issueObj.RestURL)/watchers?username=$w" + + Write-Debug "[Remove-JiraIssueWatcher] Preparing for blastoff!" + $rawResult = Invoke-JiraMethod -Method Delete -URI $url -Credential $Credential + } + } + + end + { + Write-Debug "[Remove-JiraIssueWatcher] Complete" + } +} + + From cea951d8086ffaea284acce7f7e17b51787eb8fe Mon Sep 17 00:00:00 2001 From: Eugene Bekker Date: Tue, 24 Jan 2017 16:49:59 -0500 Subject: [PATCH 018/102] Fixing unit tests --- PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 | 10 +-- PSJira/Public/Add-JiraIssueWatcher.ps1 | 2 - PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 | 13 ++-- .../Public/Remove-JiraIssueWatcher.Tests.ps1 | 68 +++++++++++++++++++ PSJira/Public/Remove-JiraIssueWatcher.ps1 | 2 - 5 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 PSJira/Public/Remove-JiraIssueWatcher.Tests.ps1 diff --git a/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 b/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 index 26a9d86b..e2276394 100644 --- a/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 +++ b/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 @@ -24,17 +24,13 @@ InModuleScope PSJira { } } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watcher"} { + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { if ($ShowMockData) { Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan Write-Host " [URI] $URI" -ForegroundColor Cyan } - - # This data was created from a GUI REST client, then sanitized. A lot of extra data was also removed to save space. - # Many Bothans died to bring us this information. - ConvertFrom-Json2 $restResponse } # Generic catch-all. This will throw an exception if we forgot to mock something. @@ -51,7 +47,7 @@ InModuleScope PSJira { It "Adds a Watcher to an issue in JIRA" { $WatcherResult = Add-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey - $WatcherResult | Should Not BeNullOrEmpty + $WatcherResult | Should BeNullOrEmpty # Get-JiraIssue should be used to identiyf the issue parameter Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It @@ -70,5 +66,3 @@ InModuleScope PSJira { } } } - - diff --git a/PSJira/Public/Add-JiraIssueWatcher.ps1 b/PSJira/Public/Add-JiraIssueWatcher.ps1 index 15047b04..12dedd5d 100644 --- a/PSJira/Public/Add-JiraIssueWatcher.ps1 +++ b/PSJira/Public/Add-JiraIssueWatcher.ps1 @@ -92,5 +92,3 @@ Write-Debug "[Add-JiraIssueWatcher] Complete" } } - - diff --git a/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 b/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 index ffe568b0..ad01cdad 100644 --- a/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 +++ b/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 @@ -12,15 +12,15 @@ InModuleScope PSJira { $issueKey = 'IT-3676' ## Sample straight from the API: - ## https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssueWatchers + ## https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssueWatchers $restResult = @" { - "self": "http://www.example.com/jira/rest/api/2/issue/EX-1/watchers", + "self": "$jiraServer/jira/rest/api/2/issue/EX-1/watchers", "isWatching": false, "watchCount": 1, "watchers": [ { - "self": "http://www.example.com/jira/rest/api/2/user?username=fred", + "self": "$jiraServer/jira/rest/api/2/user?username=fred", "name": "fred", "displayName": "Fred F. User", "active": false @@ -71,8 +71,9 @@ InModuleScope PSJira { $watchers = Get-JiraIssueWatchers -Issue $issueKey $watchers | Should Not BeNullOrEmpty @($watchers).Count | Should Be 1 - $watchers.name | Should Be "fred" - $watchers.self | Should Be "$jiraServer/rest/api/2/user?username=fred" + $watchers.Name | Should Be "fred" + $watchers.DisplayName | Should Be "Fred F. User" + $watchers.RestUrl | Should Be "$jiraServer/jira/rest/api/2/user?username=fred" # Get-JiraIssue should be called to identify the -Issue parameter Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It @@ -98,5 +99,3 @@ InModuleScope PSJira { } } } - - diff --git a/PSJira/Public/Remove-JiraIssueWatcher.Tests.ps1 b/PSJira/Public/Remove-JiraIssueWatcher.Tests.ps1 new file mode 100644 index 00000000..34e2c374 --- /dev/null +++ b/PSJira/Public/Remove-JiraIssueWatcher.Tests.ps1 @@ -0,0 +1,68 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + $ShowMockData = $false + + $jiraServer = 'http://jiraserver.example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + + Describe "Remove-JiraIssueWatcher" { + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue -ModuleName PSJira { + [PSCustomObject] @{ + ID = $issueID; + Key = $issueKey; + RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; + } + } + + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'DELETE' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers?username=fred"} { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + Write-Host " [URI] $URI" -ForegroundColor Cyan + } + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed + Write-Host " [Method] $Method" -ForegroundColor DarkRed + Write-Host " [URI] $URI" -ForegroundColor DarkRed + throw "Unidentified call to Invoke-JiraMethod" + } + + ############# + # Tests + ############# + + It "Removes a Watcher from an issue in JIRA" { + $WatcherResult = Remove-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be used to identiyf the issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + + # Invoke-JiraMethod should be used to add the Watcher + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Accepts pipeline input from Get-JiraIssue" { + $WatcherResult = Get-JiraIssue -InputObject $issueKey | Remove-JiraIssueWatcher -Watcher 'fred' + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + } +} diff --git a/PSJira/Public/Remove-JiraIssueWatcher.ps1 b/PSJira/Public/Remove-JiraIssueWatcher.ps1 index 04d27ac6..f43c3043 100644 --- a/PSJira/Public/Remove-JiraIssueWatcher.ps1 +++ b/PSJira/Public/Remove-JiraIssueWatcher.ps1 @@ -90,5 +90,3 @@ Write-Debug "[Remove-JiraIssueWatcher] Complete" } } - - From addf6792d87382aebe11ffaf9042725e1038410a Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 8 Feb 2017 15:06:04 +0100 Subject: [PATCH 019/102] renamed variable renamed variable to be more explicit --- PSJira/Public/Get-JiraComponent.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index bbdc8485..989f3400 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -29,7 +29,8 @@ function Get-JiraComponent [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'ID')] - [String[]] $Id, + [Alias("Id")] + [String[]] $ComponentId, # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] @@ -60,11 +61,11 @@ function Get-JiraComponent process { if ($InputObject -and ($InputObject.PSObject.TypeNames[0] -eq 'PSJira.Project')) { - $Id = @($InputObject.Components | select -ExpandProperty id) + $ComponentId = @($InputObject.Components | select -ExpandProperty id) } - if ($Id) + if ($ComponentId) { - foreach ($i in $Id) + foreach ($i in $ComponentId) { Write-Debug "[Get-JiraComponent] Processing project [$i]" $thisUri = "$uri/${i}" From e40e1b90a9144cffb6af1447a580765861bd22d4 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 8 Feb 2017 15:07:25 +0100 Subject: [PATCH 020/102] minor tweaks and cleanup --- PSJira/Public/Get-JiraComponent.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index 989f3400..b783aac0 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -90,8 +90,6 @@ function Get-JiraComponent end { - Write-Debug "Complete" + Write-Debug "[Get-JiraComponent] Complete" } } - - From 05f9d104ee2d5bf8e5479caed2a972f4c652edd4 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 8 Feb 2017 15:11:51 +0100 Subject: [PATCH 021/102] improved parameters * renaming of parameter name to be more explicit * defining default parameterSet --- PSJira/Public/Get-JiraComponent.ps1 | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index b783aac0..b64264df 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -23,24 +23,24 @@ function Get-JiraComponent .OUTPUTS [PSJira.Component] #> - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'ByID')] param( + # The Project ID or project key of a project to search + [Parameter(ParameterSetName = 'ByProject', + ValueFromPipeline, + Mandatory = $true)] + $Project, + # The Component ID [Parameter(Mandatory = $true, Position = 0, - ParameterSetName = 'ID')] + ParameterSetName = 'ByID')] [Alias("Id")] - [String[]] $ComponentId, + [int[]] $ComponentId, # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] - [System.Management.Automation.PSCredential] $Credential, - - # Credentials to use to connect to Jira - [Parameter(Mandatory = $true, - ValueFromPipeline, - ParameterSetName = 'InputObject')] - [PSObject] $InputObject + [System.Management.Automation.PSCredential] $Credential ) begin @@ -60,8 +60,8 @@ function Get-JiraComponent process { - if ($InputObject -and ($InputObject.PSObject.TypeNames[0] -eq 'PSJira.Project')) { - $ComponentId = @($InputObject.Components | select -ExpandProperty id) + if ($Project -and ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project')) { + $ComponentId = @($Project.Components | select -ExpandProperty id) } if ($ComponentId) { From 445120996e7191f4c063064d3fced302bab53875 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 8 Feb 2017 15:14:34 +0100 Subject: [PATCH 022/102] expose API endpoint _project/{projectIdOrKey}/components_ --- PSJira/Public/Get-JiraComponent.ps1 | 40 +++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index b64264df..ca36552a 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -17,6 +17,9 @@ function Get-JiraComponent .EXAMPLE Get-JiraProject Project1 | Get-JiraComponent -Credential $cred Returns information about all components within project 'Project1' + .EXAMPLE + Get-JiraComponent ABC,DEF + Return information about all components within projects 'ABC' and 'DEF' .INPUTS [String[]] Component ID [PSCredential] Credentials to use to connect to Jira @@ -55,20 +58,47 @@ function Get-JiraComponent throw $err } - $uri = "$server/rest/api/latest/component" + $uri = "$server/rest/api/latest" } process { - if ($Project -and ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project')) { - $ComponentId = @($Project.Components | select -ExpandProperty id) + if ($Project) + { + if ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project') { + $ComponentId = @($Project.Components | select -ExpandProperty id) + } else { + foreach ($p in $Project) + { + if ($p -is [string]) + { + Write-Debug "[Get-JiraComponent] Processing project [$p]" + $thisUri = "$uri/project/${p}/components" + + Write-Debug "[Get-JiraComponent] Preparing for blastoff!" + + $result = Invoke-JiraMethod -Method Get -URI $thisUri -Credential $Credential + if ($result) + { + Write-Debug "[Get-JiraComponent] Converting to object" + $obj = ConvertTo-JiraComponent -InputObject $result + + Write-Debug "[Get-JiraComponent] Outputting result" + Write-Output $obj + } else { + Write-Debug "[Get-JiraComponent] No results were returned from Jira" + Write-Debug "[Get-JiraComponent] No results were returned from Jira for component [$i]" + } + } + } + } } if ($ComponentId) { foreach ($i in $ComponentId) { - Write-Debug "[Get-JiraComponent] Processing project [$i]" - $thisUri = "$uri/${i}" + Write-Debug "[Get-JiraComponent] Processing component [$i]" + $thisUri = "$uri/component/${i}" Write-Debug "[Get-JiraComponent] Preparing for blastoff!" From 7bad1aa32699d0160df8519a06d7dfd330c615bd Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 10:34:46 +0100 Subject: [PATCH 023/102] fixed merge from master --- PSJira/Public/New-JiraIssue.ps1 | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index 672fa49c..937dab48 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -53,8 +53,6 @@ function New-JiraIssue [Parameter(Mandatory = $false)] [String] $Parent, - [Parameter(Mandatory = $false)] - [Parameter(Mandatory = $false)] [Hashtable] $Fields, @@ -93,13 +91,6 @@ function New-JiraIssue { throw "Unable to identify Jira issue type [$IssueType]. Use Get-JiraIssueType for more information." } - } - - if ($Parent.key) - { - $Parent = Get-JiraIssue $Parent.key -Credential $Credential - } elseif ($Parent) { - $Parent = Get-JiraIssue $Parent -Credential $Credential } process @@ -205,4 +196,4 @@ function New-JiraIssue { Write-Debug "[New-JiraIssue] Completing New-JiraIssue" } -} +} \ No newline at end of file From 2740a647ef353b786ebc4587b3216de104e60cdf Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 10:36:03 +0100 Subject: [PATCH 024/102] refactored refactored according to current PSJira styling --- PSJira/Public/Remove-JiraRemoteLink.ps1 | 80 ++++++++++++++++++++----- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/PSJira/Public/Remove-JiraRemoteLink.ps1 b/PSJira/Public/Remove-JiraRemoteLink.ps1 index 4b73dde2..b77f8e06 100644 --- a/PSJira/Public/Remove-JiraRemoteLink.ps1 +++ b/PSJira/Public/Remove-JiraRemoteLink.ps1 @@ -1,46 +1,98 @@ function Remove-JiraRemoteLink -{ - #https://docs.atlassian.com/jira/REST/latest/#d2e928 - [CmdletBinding()] +{<# + .Synopsis + Removes a remote link from a JIRA issue + .DESCRIPTION + This function removes a remote link from a JIRA issue. + .EXAMPLE + Remove-JiraRemoteLink Project1-1001 10000,20000 + Removes two remote link from issue "Project1-1001" + .EXAMPLE + Get-JiraIssue -Query "project = Project1" | Remove-JiraRemoteLink 10000 + Removes a specific remote link from all issues in project "Project1" + .INPUTS + [PSJira.Issue[]] The JIRA issue from which to delete a link + .OUTPUTS + This function returns no output. + #> + [CmdletBinding(SupportsShouldProcess = $true, + ConfirmImpact = 'High')] param( + # Issue from which to delete a remote link [Parameter(ValueFromPipelineByPropertyName = $true, - ParameterSetName = 'ByIssueKey', ValueFromPipeline = $true, Mandatory = $true, Position = 0 )] - [ValidateNotNullOrEmpty()] - [String[]]$Key, + [Alias("Key")] + [Object[]] $Issue, + # Id of the remote link to delete [Parameter(Mandatory = $true)] - [string]$LinkId, + [Int[]] $LinkId, # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] - [System.Management.Automation.PSCredential] $Credential + [PSCredential] $Credential, + + [Switch] $force ) Begin { - Write-Debug "[Get-JiraRemoteLink] Reading server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + try + { + Write-Debug "[Remove-JiraRemoteLink] Reading Jira server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + } catch { + $err = $_ + Write-Debug "[Remove-JiraRemoteLink] Encountered an error reading configuration data." + throw $err + } + + $restUrl = "$server/rest/api/latest/issue/{0}/remotelink/{1}" + + if ($Force) + { + Write-Debug "[Remove-JiraRemoteLink] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" + $oldConfirmPreference = $ConfirmPreference + $ConfirmPreference = 'None' + } } Process { - foreach ($k in $key) + foreach ($k in $Issue) { Write-Debug "[Remove-JiraRemoteLink] Processing issue key [$k]" - $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink/${linkId}" + $issueObj = Get-JiraIssue $k -Credential $Credential + + foreach ($l in $LinkId) + { + $thisUrl = $restUrl -f $k,$l + Write-Debug "[Remove-JiraRemoteLink] RemoteLink URL: [$thisUrl]" - Write-Debug "[Remove-JiraRemoteLink] Preparing for blastoff!" - Invoke-JiraMethod -Method Delete -URI $issueURL -Credential $Credential + Write-Debug "[Remove-JiraRemoteLink] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($issueObj.Key, "Remove RemoteLink from [$issueObj] from JIRA")) + { + Write-Debug "[Remove-JiraRemoteLink] Preparing for blastoff!" + Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential + } else { + Write-Debug "[Remove-JiraRemoteLink] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" + } + } } } End { + if ($Force) + { + Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" + $ConfirmPreference = $oldConfirmPreference + } + Write-Debug "[Remove-JiraRemoteLink] Complete" } } From a27a0a872e9537990410880989af00115879e93d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 10:36:40 +0100 Subject: [PATCH 025/102] added UnitTests for Remove-JiraRemoteLink --- PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 diff --git a/PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 b/PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 new file mode 100644 index 00000000..64600359 --- /dev/null +++ b/PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 @@ -0,0 +1,117 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + # This is intended to be a parameter to the test, but Pester currently does not allow parameters to be passed to InModuleScope blocks. + # For the time being, we'll need to hard-code this and adjust it as desired. + $ShowMockData = $false + $ShowDebugData = $false + + $jiraServer = 'http://jiraserver.example.com' + + $testIssueKey = 'EX-1' + + $testLink = @" +{ + "id": 10000, + "self": "http://www.example.com/jira/rest/api/issue/MKY-1/remotelink/10000", + "globalId": "system=http://www.mycompany.com/support&id=1", + "application": { + "type": "com.acme.tracker", + "name": "My Acme Tracker" + }, + "relationship": "causes", + "object": { + "url": "http://www.mycompany.com/support?id=1", + "title": "TSTSUP-111", + "summary": "Crazy customer support issue", + "icon": { + "url16x16": "http://www.mycompany.com/support/ticket.png", + "title": "Support Ticket" + } + } +} +"@ + + Describe "Remove-JiraRemoteLink" { + + Mock Write-Debug -ModuleName PSJira { + if ($ShowDebugData) + { + Write-Host -Object "[DEBUG] $Message" -ForegroundColor Yellow + } + } + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue { + [PSCustomObject] @{ + 'RestURL' = 'https://jira.example.com/rest/api/2/issue/12345' + 'Key' = $testIssueKey + } + } + + Mock Get-JiraRemoteLink { + ConvertFrom-Json2 $testLink + } + + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'DELETE'} { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-JiraMethod with DELETE method" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + Write-Host " [URI] $URI" -ForegroundColor Cyan + } + # This REST method should produce no output + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed + Write-Host " [Method] $Method" -ForegroundColor DarkRed + Write-Host " [URI] $URI" -ForegroundColor DarkRed + throw "Unidentified call to Invoke-JiraMethod" + } + + ############# + # Tests + ############# + + It "Accepts a issue key to the -Issue parameter" { + { Remove-JiraRemoteLink -Issue $testIssueKey -LinkId 10000 -Force } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Accepts a PSJira.Issue object to the -Issue parameter" { + $Issue = Get-JiraIssue $testIssueKey + { Remove-JiraRemoteLink -Issue $Issue -LinkId 10000 -Force } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Accepts pipeline input from Get-JiraIssue" { + { Get-JiraIssue $testIssueKey | Remove-JiraRemoteLink -LinkId 10000 -Force } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Accepts the output of Get-JiraRemoteLink" { + $remoteLink = Get-JiraRemoteLink $testIssueKey + { Remove-JiraRemoteLink -Issue $testIssueKey -LinkId $remoteLink.id -Force } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Removes a group from JIRA" { + { Remove-JiraRemoteLink -Issue $testIssueKey -LinkId 10000 -Force } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Provides no output" { + Remove-JiraRemoteLink -Issue $testIssueKey -LinkId 10000 -Force | Should BeNullOrEmpty + } + } +} + + From e0cd8ca194fd676353a1f2f336bac64ea334c7d3 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 10:58:18 +0100 Subject: [PATCH 026/102] refactored refactored according to current PSJira styling --- PSJira/Public/Get-JiraRemoteLink.ps1 | 61 +++++++++++++++++++++------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 index 70bf8549..78c332d4 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -1,44 +1,77 @@ function Get-JiraRemoteLink { - #https://docs.atlassian.com/jira/REST/latest/#d2e928 - #Get-JiraRemoteLink -apiURi $JiraRestURi -cred $cred -issueID "HCF-966" - #Get-JiraRemoteLink -apiURi $JiraRestURi -cred $cred -issueID "HCF-120" + <# + .Synopsis + Returns a remote link from a Jira issue + .DESCRIPTION + This function returns information on remote links from a JIRA issue. + .EXAMPLE + Get-JiraRemoteLink -Issue Project1-1000 -Credential $cred + Returns information about all remote links from the issue "Project1-1000" + .EXAMPLE + Get-JiraRemoteLink -Issue Project1-1000 -LinkId 100000 -Credential $cred + Returns information about a specific remote link from the issue "Project1-1000" + .INPUTS + [Object[]] The issue to look up in JIRA. This can be a String or a PSJira.Issue object. + .OUTPUTS + [PSJira.Link] + #> [CmdletBinding()] param( [Parameter(ValueFromPipelineByPropertyName = $true, - ParameterSetName = 'ByIssueKey', ValueFromPipeline = $true, Mandatory = $true, Position = 0 )] - [ValidateNotNullOrEmpty()] - [String[]]$Key, + [Alias("Key")] + [String[]]$Issue, # Get a single link by it's id - [int]$linkId, + [Int[]]$LinkId, # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] - [System.Management.Automation.PSCredential] $Credential + [PSCredential] $Credential ) Begin { Write-Debug "[Get-JiraRemoteLink] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + Write-Debug "[Get-JiraRemoteLink] ParameterSetName=$($PSCmdlet.ParameterSetName)" + + Write-Debug "[Get-JiraRemoteLink] Building URI for REST call" + $linkUrl = "$server/rest/api/latest/issue/{0}/remotelink" } Process { - foreach ($k in $key) + foreach ($k in $Issue) { Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" - $issueURL = "$($server)/rest/api/latest/issue/${k}/remotelink" - if ($linkId) - { $issueURL += "/$linkId" } + foreach ($l in $LinkId) + { + $thisUrl = $linkUrl -f $k + + if ($linkId) + { $thisUrl += "/$l" } + + Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential + + if ($result) + { + Write-Debug "[Get-JiraRemoteLink] Converting results to PSJira.Group" + $obj = ConvertTo-JiraLink -InputObject $result - Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" - Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential + Write-Debug "[Get-JiraRemoteLink] Outputting results" + Write-Output $obj + } else { + Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" + Write-Verbose "No results were returned from JIRA." + } + } } } From 82c676a06801c559a8d103f7301e80b9d2d6e638 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 12:35:11 +0100 Subject: [PATCH 027/102] added ConvertTo-JiraLink & UnitTests --- PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 | 61 ++++++++++++++ PSJira/Internal/ConvertTo-JiraLink.ps1 | 88 ++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 create mode 100644 PSJira/Internal/ConvertTo-JiraLink.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 new file mode 100644 index 00000000..d66fae11 --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 @@ -0,0 +1,61 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + Describe "ConvertTo-JiraLink" { + function defProp($obj, $propName, $propValue) + { + It "Defines the '$propName' property" { + $obj.$propName | Should Be $propValue + } + } + + $jiraServer = 'http://jiraserver.example.com' + $LinkID = "10000" + + $sampleJson = @" +{ + "id": 10000, + "self": "http://jiraserver.example.com/rest/api/issue/MKY-1/remotelink/10000", + "globalId": "system=http://www.mycompany.com/support&id=1", + "application": { + "type": "com.acme.tracker", + "name": "My Acme Tracker" + }, + "relationship": "causes", + "object": { + "url": "http://www.mycompany.com/support?id=1", + "title": "TSTSUP-111", + "summary": "Crazy customer support issue", + "icon": { + "url16x16": "http://www.mycompany.com/support/ticket.png", + "title": "Support Ticket" + }, + "status": { + "resolved": true, + "icon": { + "url16x16": "http://www.mycompany.com/support/resolved.png", + "title": "Case Closed", + "link": "http://www.mycompany.com/support?id=1&details=closed" + } + } + } +} +"@ + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson + + $r = ConvertTo-JiraLink -InputObject $sampleObject + + It "Creates a PSObject out of JSON input" { + $r | Should Not BeNullOrEmpty + } + + It "Sets the type name to PSJira.Link" { + (Get-Member -InputObject $r).TypeName | Should Be 'PSJira.Link' + } + + defProp $r 'id' $LinkId + defProp $r 'RestUrl' "$jiraServer/rest/api/issue/MKY-1/remotelink/10000" + } +} diff --git a/PSJira/Internal/ConvertTo-JiraLink.ps1 b/PSJira/Internal/ConvertTo-JiraLink.ps1 new file mode 100644 index 00000000..97c52419 --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraLink.ps1 @@ -0,0 +1,88 @@ +function ConvertTo-JiraLink +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject + ) + + process + { + foreach ($i in $InputObject) + { +# Write-Debug "[ConvertTo-JiraLink] Processing object: '$i'" + +# Write-Debug "[ConvertTo-JiraLink] Defining standard properties" + $props = @{ + 'Id' = $i.id; + 'RestUrl' = $i.self; + } + + if ($i.globalId) {$props.globalId = $i.globalId} + if ($i.application) { + $props.application = New-Object PSObject -Prop @{ + type = $i.application.type + name = $i.application.name + } + } + if ($i.relationship) {$props.relationship = $i.relationship} + if ($i.object) { + if ($i.object.icon) + { + $icon = New-Object PSObject -Prop @{ + title = $i.object.icon.title + url16x16 = $i.object.icon.url16x16 + } + } else { $icon = $null } + + if ($i.object.status.icon) + { + $statusIcon = New-Object PSObject -Prop @{ + link = $i.object.status.icon.link + title = $i.object.status.icon.title + url16x16 = $i.object.status.icon.url16x16 + } + } else { $statusIcon = $null } + + if ($i.object.status) + { + $status = New-Object PSObject -Prop @{ + resolved = $i.object.status.resolved + icon = $statusIcon + } + } else { $status = $null } + + $props.object = New-Object PSObject -Prop @{ + url = $i.object.url + title = $i.object.title + summary = $i.object.summary + icon = $icon + status = $status + } + } + +# Write-Debug "[ConvertTo-JiraLink] Creating PSObject out of properties" + $result = New-Object -TypeName PSObject -Property $props + +# Write-Debug "[ConvertTo-JiraLink] Inserting type name information" + $result.PSObject.TypeNames.Insert(0, 'PSJira.Link') + +# Write-Debug "[ConvertTo-JiraLink] Inserting custom toString() method" + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Id)" + } + +# Write-Debug "[ConvertTo-JiraLink] Outputting object" + Write-Output $result + } + } + + end + { +# Write-Debug "[ConvertTo-JiraLink] Complete" + } +} + + From 925e7a43f9fade0add8aa41b464b4229868a43ef Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 12:36:16 +0100 Subject: [PATCH 028/102] removed array of LinkId --- PSJira/Public/Get-JiraRemoteLink.ps1 | 33 +++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 index 78c332d4..080c6e18 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -27,7 +27,7 @@ function Get-JiraRemoteLink [String[]]$Issue, # Get a single link by it's id - [Int[]]$LinkId, + [Int]$LinkId, # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] @@ -50,27 +50,24 @@ function Get-JiraRemoteLink foreach ($k in $Issue) { Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" - foreach ($l in $LinkId) - { - $thisUrl = $linkUrl -f $k + $thisUrl = $linkUrl -f $k - if ($linkId) - { $thisUrl += "/$l" } + if ($linkId) + { $thisUrl += "/$l" } - Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential + Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential - if ($result) - { - Write-Debug "[Get-JiraRemoteLink] Converting results to PSJira.Group" - $obj = ConvertTo-JiraLink -InputObject $result + if ($result) + { + Write-Debug "[Get-JiraRemoteLink] Converting results to PSJira.Group" + $obj = ConvertTo-JiraLink -InputObject $result - Write-Debug "[Get-JiraRemoteLink] Outputting results" - Write-Output $obj - } else { - Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" - Write-Verbose "No results were returned from JIRA." - } + Write-Debug "[Get-JiraRemoteLink] Outputting results" + Write-Output $obj + } else { + Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" + Write-Verbose "No results were returned from JIRA." } } } From 809b63528b1281f6336bc20efa559156793f52b2 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 9 Feb 2017 13:33:57 +0100 Subject: [PATCH 029/102] added UnitTests for Get-JiraRemoteLink --- PSJira/Public/Get-JiraRemoteLink.Tests.ps1 | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 PSJira/Public/Get-JiraRemoteLink.Tests.ps1 diff --git a/PSJira/Public/Get-JiraRemoteLink.Tests.ps1 b/PSJira/Public/Get-JiraRemoteLink.Tests.ps1 new file mode 100644 index 00000000..e2759777 --- /dev/null +++ b/PSJira/Public/Get-JiraRemoteLink.Tests.ps1 @@ -0,0 +1,96 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + $showMockData = $false + + $jiraServer = 'http://jiraserver.example.com' + + $testIssueKey = 'MKY-1' + + $restResult = @" + { + "id": 10000, + "self": "http://jiraserver.example.com/rest/api/issue/MKY-1/remotelink/10000", + "globalId": "system=http://www.mycompany.com/support&id=1", + "application": { + "type": "com.acme.tracker", + "name": "My Acme Tracker" + }, + "relationship": "causes", + "object": { + "url": "http://www.mycompany.com/support?id=1", + "title": "TSTSUP-111", + "summary": "Crazy customer support issue", + "icon": { + "url16x16": "http://www.mycompany.com/support/ticket.png", + "title": "Support Ticket" + } + } + } +"@ + + Describe "Get-JiraRemoteLink" { + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue { + [PSCustomObject] @{ + 'RestURL' = 'https://jira.example.com/rest/api/2/issue/12345' + 'Key' = $testIssueKey + } + } + + # Searching for a group. + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get'} { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-JiraMethod with GET method" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + Write-Host " [URI] $URI" -ForegroundColor Cyan + } + ConvertFrom-Json2 -InputObject $restResult + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed + Write-Host " [Method] $Method" -ForegroundColor DarkRed + Write-Host " [URI] $URI" -ForegroundColor DarkRed + throw "Unidentified call to Invoke-JiraMethod" + } + +# Mock Write-Debug { +# Write-Host "DEBUG: $Message" -ForegroundColor Yellow +# } + + ############# + # Tests + ############# + + It "Gets information of all remote link from a Jira issue" { + $getResult = Get-JiraRemoteLink -Issue $testIssueKey + $getResult | Should Not BeNullOrEmpty + } + + It "Converts the output object to PSJira.Link" { + $getResult = Get-JiraRemoteLink -Issue $testIssueKey + (Get-Member -InputObject $getResult).TypeName | Should Be 'PSJira.Link' + } + + It "Returns all available properties about the returned link object" { + $getResult = Get-JiraRemoteLink -Issue $testIssueKey + $restObj = ConvertFrom-Json2 -InputObject $restResult + + $getResult.RestUrl | Should Be $restObj.self + $getResult.Id | Should Be $restObj.Id + $getResult.globalId | Should Be $restObj.globalId + } + } +} + + From 1858257193fd93ebd4f7a07064c40cbb2a6ba478 Mon Sep 17 00:00:00 2001 From: Eugene Bekker Date: Fri, 10 Feb 2017 16:47:06 -0500 Subject: [PATCH 030/102] Slight code style correction Also, something to force PR #73 checks to re-execute. --- PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 b/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 index e2276394..f1478781 100644 --- a/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 +++ b/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 @@ -25,8 +25,7 @@ InModuleScope PSJira { } Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { - if ($ShowMockData) - { + if ($ShowMockData) { Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan Write-Host " [URI] $URI" -ForegroundColor Cyan From c5176a6831bc5b2be28388061cff9abd1ee441c1 Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Thu, 23 Feb 2017 15:51:16 -0800 Subject: [PATCH 031/102] Implemented ability to add worklog items to an issue. --- .../ConvertTo-JiraWorklogitem.Tests.ps1 | 88 +++++++++++ PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 | 92 +++++++++++ PSJira/PSJira.psd1 | 2 +- PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 | 122 +++++++++++++++ PSJira/Public/Add-JiraIssueWorklog.ps1 | 143 ++++++++++++++++++ 5 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 PSJira/Internal/ConvertTo-JiraWorklogitem.Tests.ps1 create mode 100644 PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 create mode 100644 PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 create mode 100644 PSJira/Public/Add-JiraIssueWorklog.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraWorklogitem.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraWorklogitem.Tests.ps1 new file mode 100644 index 00000000..21358932 --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraWorklogitem.Tests.ps1 @@ -0,0 +1,88 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + Describe "ConvertTo-JiraWorklogitem" { + function defProp($obj, $propName, $propValue) + { + It "Defines the '$propName' property" { + $obj.$propName | Should Be $propValue + } + } + + $jiraServer = 'http://jiraserver.example.com' + $jiraUsername = 'powershell-test' + $jiraUserDisplayName = 'PowerShell Test User' + $jiraUserEmail = 'noreply@example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + $worklogitemID = 73040 + $commentBody = "Test description" + $worklogTimeSpent = "1h" + $worklogTimeSpentSeconds = "3600" + + $sampleJson = @" +{ + "id": "$worklogitemID", + "self": "$jiraServer/rest/api/2/issue/$issueID/worklog/$worklogitemID", + "comment": "Test description", + "created": "2015-05-01T16:24:38.000-0500", + "updated": "2015-05-01T16:24:38.000-0500", + "started": "2017-02-23T22:21:00.000-0500", + "timeSpent": "1h", + "timeSpentSeconds": "3600", + "author": { + "self": "$jiraServer/rest/api/2/user?username=powershell-test", + "name": "$jiraUsername", + "emailAddress": "$jiraUserEmail", + "avatarUrls": { + "48x48": "$jiraServer/secure/useravatar?avatarId=10202", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10202", + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10202", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10202" + }, + "displayName": "$jiraUserDisplayName", + "active": true + }, + "updateAuthor": { + "self": "$jiraServer/rest/api/2/user?username=powershell-test", + "name": "powershell-test", + "emailAddress": "$jiraUserEmail", + "avatarUrls": { + "48x48": "$jiraServer/secure/useravatar?avatarId=10202", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10202", + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10202", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10202" + }, + "displayName": "$jiraUserDisplayName", + "active": true + } +} +"@ + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson + + It "Creates a PSObject out of JSON input" { + $r = ConvertTo-JiraWorklogitem -InputObject $sampleObject + $r | Should Not BeNullOrEmpty + } + + It "Sets the type name to PSJira.WorklogItem" { + $r = ConvertTo-JiraWorklogitem -InputObject $sampleObject + $r.PSObject.TypeNames[0] | Should Be 'PSJira.WorklogItem' + } + + $r = ConvertTo-JiraWorklogitem -InputObject $sampleObject + + defProp $r 'Id' $worklogitemID + defProp $r 'Comment' $commentBody + defProp $r 'RestUrl' "$jiraServer/rest/api/2/issue/41701/worklog/$worklogitemID" + defProp $r 'Created' (Get-Date '2015-05-01T16:24:38.000-0500') + defProp $r 'Updated' (Get-Date '2015-05-01T16:24:38.000-0500') + defProp $r 'Started' (Get-Date '2017-02-23T22:21:00.000-0500') + defProp $r 'TimeSpent' $worklogTimeSpent + defProp $r 'TimeSpentSeconds' $worklogTimeSpentSeconds + } +} + + diff --git a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 b/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 new file mode 100644 index 00000000..9ccb54a7 --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 @@ -0,0 +1,92 @@ +function ConvertTo-JiraWorklogitem +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject + ) + + process + { + foreach ($i in $InputObject) + { +# Write-Debug "[ConvertTo-JiraWorklogitem] Processing object: '$i'" + +# Write-Debug "[ConvertTo-JiraWorklogitem] Defining standard properties" + $props = @{ + 'ID' = $i.id; + 'Visibility' = $i.visibility; + 'Comment' = $i.comment; + 'RestUrl' = $i.self; + } + + # These fields should typically exist on an object returned from Jira, + # but this provides a bit of extra error checking and safety + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for author" + if ($i.author) + { + $props.Author = ConvertTo-JiraUser -InputObject $i.author + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for update author" + if ($i.updateAuthor) + { + $props.UpdateAuthor = ConvertTo-JiraUser -InputObject $i.updateAuthor + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for created date" + if ($i.created) + { + $props.Created = (Get-Date ($i.created)) + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for updated date" + if ($i.updated) + { + $props.Updated = (Get-Date ($i.updated)) + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for started date" + if ($i.started) + { + $props.Started = (Get-Date ($i.started)) + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for time spent" + if ($i.timeSpent) + { + $props.TimeSpent = $i.timeSpent + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Checking for time spent in seconds" + if ($i.timeSpentSeconds) + { + $props.TimeSpentSeconds = $i.timeSpentSeconds + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Creating PSObject out of properties" + $result = New-Object -TypeName PSObject -Property $props + +# Write-Debug "[ConvertTo-JiraWorklogitem] Inserting type name information" + $result.PSObject.TypeNames.Insert(0, 'PSJira.Worklogitem') + +# Write-Debug "[ConvertTo-JiraWorklogitem] Inserting custom toString() method" + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Body)" + } + +# Write-Debug "[ConvertTo-JiraWorklogitem] Outputting object" + Write-Output $result + } + } + + end + { +# Write-Debug "[ConvertTo-JiraWorklogitem] Complete" + } +} + + diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index 1252b564..954bed16 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -69,7 +69,7 @@ FormatsToProcess = 'PSJira.format.ps1xml' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Get-JiraComponent', 'Format-Jira', +FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Add-JiraIssueWorklog','Get-JiraComponent', 'Format-Jira', 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', diff --git a/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 b/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 new file mode 100644 index 00000000..bf485db9 --- /dev/null +++ b/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 @@ -0,0 +1,122 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + $ShowMockData = $false + + $jiraServer = 'http://jiraserver.example.com' + $jiraUsername = 'powershell-test' + $jiraUserDisplayName = 'PowerShell Test User' + $jiraUserEmail = 'noreply@example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + $worklogitemID = 73040 + + $restResponse = @" +{ + "id": "$worklogitemID", + "self": "$jiraServer/rest/api/latest/issue/$issueID/worklog/$worklogitemID", + "comment": "Test description", + "created": "2015-05-01T16:24:38.000-0500", + "updated": "2015-05-01T16:24:38.000-0500", + "started": "2017-02-23T22:21:00.000-0500", + "timeSpent": "1h", + "timeSpentSeconds": "3600", + "author": { + "self": "$jiraServer/rest/api/2/user?username=powershell-test", + "name": "$jiraUsername", + "emailAddress": "$jiraUserEmail", + "avatarUrls": { + "48x48": "$jiraServer/secure/useravatar?avatarId=10202", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10202", + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10202", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10202" + }, + "displayName": "$jiraUserDisplayName", + "active": true + }, + "updateAuthor": { + "self": "$jiraServer/rest/api/2/user?username=powershell-test", + "name": "powershell-test", + "emailAddress": "$jiraUserEmail", + "avatarUrls": { + "48x48": "$jiraServer/secure/useravatar?avatarId=10202", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10202", + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10202", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10202" + }, + "displayName": "$jiraUserDisplayName", + "active": true + } +} +"@ + + Describe "Add-JiraIssueWorklog" { + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue -ModuleName PSJira { + [PSCustomObject] @{ + ID = $issueID; + Key = $issueKey; + RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; + } + } + + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/worklog"} { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + Write-Host " [URI] $URI" -ForegroundColor Cyan + } + + # This data was created from a GUI REST client, then sanitized. A lot of extra data was also removed to save space. + # Many Bothans died to bring us this information. + ConvertFrom-Json2 $restResponse + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed + Write-Host " [Method] $Method" -ForegroundColor DarkRed + Write-Host " [URI] $URI" -ForegroundColor DarkRed + throw "Unidentified call to Invoke-JiraMethod" + } + + ############# + # Tests + ############# + + It "Adds a comment to an issue in JIRA" { + $commentResult = Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent "1h" -DateStarted "2018-01-01" + $commentResult | Should Not BeNullOrEmpty + + # Get-JiraIssue should be used to identify the issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + + # Invoke-JiraMethod should be used to add the comment + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Accepts pipeline input from Get-JiraIssue" { + $commentResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWorklog -Comment 'This is a test comment from Pester, using the pipeline!' -TimeSpent "1h" -DateStarted "2018-01-01" + $commentResult | Should Not BeNullOrEmpty + + # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWorklog (to identify the InputObject parameter) + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Outputs the comment as a PSJira.Worklogitem object" { + $commentResult = Add-JiraIssueWorklog -Comment 'This is a test comment from Pester.' -Issue $issueKey -TimeSpent "1h" -DateStarted "2018-01-01" + (Get-Member -InputObject $commentResult).TypeName | Should Be 'PSJira.Worklogitem' + } + } +} + + diff --git a/PSJira/Public/Add-JiraIssueWorklog.ps1 b/PSJira/Public/Add-JiraIssueWorklog.ps1 new file mode 100644 index 00000000..22d75d16 --- /dev/null +++ b/PSJira/Public/Add-JiraIssueWorklog.ps1 @@ -0,0 +1,143 @@ +function Add-JiraIssueWorklog +{ + <# + .Synopsis + Adds a worklog item to an existing JIRA issue + .DESCRIPTION + This function adds a worklog item to an existing issue in JIRA. You can optionally set the visibility of the item (All Users, Developers, or Administrators). + .EXAMPLE + Add-JiraIssueWorklog -Comment "Test comment" -Issue "TEST-001" -TimeSpent "1m" -DateStarted (Get-Date) + This example adds a simple worklog item to the issue TEST-001. + .EXAMPLE + Get-JiraIssue "TEST-002" | Add-JiraIssueWorklog "Test worklog item from PowerShell" -TimeSpent "1m" -DateStarted (Get-Date) + This example illustrates pipeline use from Get-JiraIssue to Add-JiraIssueWorklog. + .EXAMPLE + Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Add-JiraIssueWorklog "This issue has been cancelled per Vice President's orders." -TimeSpent "1m" -DateStarted (Get-Date)} + This example illustrates logging work on all projects which match a given JQL query. It would be best to validate the query first to make sure the query returns the expected issues! + .EXAMPLE + $comment = Get-Process | Format-Jira + Add-JiraIssueWorklog $c -Issue TEST-003 -TimeSpent "1m" -DateStarted (Get-Date) + This example illustrates adding a comment based on other logic to a JIRA issue. Note the use of Format-Jira to convert the output of Get-Process into a format that is easily read by users. + .INPUTS + This function can accept PSJira.Issue objects via pipeline. + .OUTPUTS + This function outputs the PSJira.Worklogitem object created. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> + [CmdletBinding()] + param( + # Comment that should be added to JIRA + [Parameter(Mandatory = $true, + Position = 0)] + [String] $Comment, + + # Issue that should be commented upon + [Parameter(Mandatory = $true, + Position = 1, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [Alias('Key')] + [Object] $Issue, + + # Time spent to be logged, in seconds + [Parameter(Mandatory = $true, + Position = 2, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [String] $TimeSpent, + + # Date/time started to be logged + [Parameter(Mandatory = $true, + Position = 3, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [String] $DateStarted, + + # Visibility of the comment - should it be publicly visible, viewable to only developers, or only administrators? + [ValidateSet('All Users','Developers','Administrators')] + [String] $VisibleRole = 'Developers', + + # Credentials to use to connect to Jira. If not specified, this function will use + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin + { + Write-Debug "[Add-JiraIssueWorklog] Begin" + # We can't validate pipeline input here, since pipeline input doesn't exist in the Begin block. + } + + process + { +# Write-Debug "[Add-JiraIssueWorklog] Checking Issue parameter" +# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') +# { +# Write-Debug "[Add-JiraIssueWorklog] Issue parameter is a PSJira.Issue object" +# $issueObj = $Issue +# } else { +# $issueKey = $Issue.ToString() +# Write-Debug "[Add-JiraIssueWorklog] Issue key is assumed to be [$issueKey] via ToString()" +# Write-Verbose "Searching for issue [$issueKey]" +# try +# { +# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential +# } catch { +# $err = $_ +# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' +# throw $err +# } +# } +# +# if (-not $issueObj) +# { +# Write-Debug "[Add-JiraIssueWorklog] No Jira issues were found for parameter [$Issue]. An exception will be thrown." +# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" +# } + + Write-Debug "[Add-JiraIssueWorklog] Obtaining a reference to Jira issue [$Issue]" + $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential + + $url = "$($issueObj.RestURL)/worklog" + + Write-Debug "[Add-JiraIssueWorklog] Creating request body from comment" + $props = @{ + 'comment' = $Comment; + 'started' = $DateStarted; + 'timeSpent' = $TimeSpent + } + + + + # If the visible role should be all users, the visibility block shouldn't be passed at + # all. JIRA returns a 500 Internal Server Error if you try to pass this block with a + # value of "All Users". + if ($VisibleRole -ne 'All Users') + { + $props.visibility = @{ + 'type' = 'role'; + 'value' = $VisibleRole; + } + } + + Write-Debug "[Add-JiraIssueWorklog] Converting to JSON" + $json = ConvertTo-Json -InputObject $props + + Write-Debug "[Add-JiraIssueWorklog] Preparing for blastoff!! $json" + $rawResult = Invoke-JiraMethod -Method Post -URI $url -Body $json -Credential $Credential + + Write-Debug "[Add-JiraIssueWorklog] Converting to custom object" + $result = ConvertTo-JiraWorklogitem -InputObject $rawResult + + Write-Debug "[Add-JiraIssueWorklog] Outputting result" + Write-Output $result + } + + end + { + Write-Debug "[Add-JiraIssueWorklog] Complete" + } +} + + From d933247da80ad7b6d81c570250b59ca6542c69d8 Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Thu, 2 Mar 2017 10:32:59 -0800 Subject: [PATCH 032/102] Fixed discrepancy between integers & strings when dealing with TimeWorked. The parameter is now universally an integer in all examples, code, and tests. --- PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 | 6 +++--- PSJira/Public/Add-JiraIssueWorklog.ps1 | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 b/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 index bf485db9..993f30f7 100644 --- a/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 +++ b/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 @@ -93,7 +93,7 @@ InModuleScope PSJira { ############# It "Adds a comment to an issue in JIRA" { - $commentResult = Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent "1h" -DateStarted "2018-01-01" + $commentResult = Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent 3600 -DateStarted "2018-01-01" $commentResult | Should Not BeNullOrEmpty # Get-JiraIssue should be used to identify the issue parameter @@ -104,7 +104,7 @@ InModuleScope PSJira { } It "Accepts pipeline input from Get-JiraIssue" { - $commentResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWorklog -Comment 'This is a test comment from Pester, using the pipeline!' -TimeSpent "1h" -DateStarted "2018-01-01" + $commentResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWorklog -Comment 'This is a test comment from Pester, using the pipeline!' -TimeSpent "3600" -DateStarted "2018-01-01" $commentResult | Should Not BeNullOrEmpty # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWorklog (to identify the InputObject parameter) @@ -113,7 +113,7 @@ InModuleScope PSJira { } It "Outputs the comment as a PSJira.Worklogitem object" { - $commentResult = Add-JiraIssueWorklog -Comment 'This is a test comment from Pester.' -Issue $issueKey -TimeSpent "1h" -DateStarted "2018-01-01" + $commentResult = Add-JiraIssueWorklog -Comment 'This is a test comment from Pester.' -Issue $issueKey -TimeSpent "3600" -DateStarted "2018-01-01" (Get-Member -InputObject $commentResult).TypeName | Should Be 'PSJira.Worklogitem' } } diff --git a/PSJira/Public/Add-JiraIssueWorklog.ps1 b/PSJira/Public/Add-JiraIssueWorklog.ps1 index 22d75d16..f7e03b67 100644 --- a/PSJira/Public/Add-JiraIssueWorklog.ps1 +++ b/PSJira/Public/Add-JiraIssueWorklog.ps1 @@ -6,17 +6,17 @@ function Add-JiraIssueWorklog .DESCRIPTION This function adds a worklog item to an existing issue in JIRA. You can optionally set the visibility of the item (All Users, Developers, or Administrators). .EXAMPLE - Add-JiraIssueWorklog -Comment "Test comment" -Issue "TEST-001" -TimeSpent "1m" -DateStarted (Get-Date) + Add-JiraIssueWorklog -Comment "Test comment" -Issue "TEST-001" -TimeSpent 60 -DateStarted (Get-Date) This example adds a simple worklog item to the issue TEST-001. .EXAMPLE - Get-JiraIssue "TEST-002" | Add-JiraIssueWorklog "Test worklog item from PowerShell" -TimeSpent "1m" -DateStarted (Get-Date) + Get-JiraIssue "TEST-002" | Add-JiraIssueWorklog "Test worklog item from PowerShell" -TimeSpent 60 -DateStarted (Get-Date) This example illustrates pipeline use from Get-JiraIssue to Add-JiraIssueWorklog. .EXAMPLE - Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Add-JiraIssueWorklog "This issue has been cancelled per Vice President's orders." -TimeSpent "1m" -DateStarted (Get-Date)} + Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Add-JiraIssueWorklog "This issue has been cancelled per Vice President's orders." -TimeSpent 60 -DateStarted (Get-Date)} This example illustrates logging work on all projects which match a given JQL query. It would be best to validate the query first to make sure the query returns the expected issues! .EXAMPLE $comment = Get-Process | Format-Jira - Add-JiraIssueWorklog $c -Issue TEST-003 -TimeSpent "1m" -DateStarted (Get-Date) + Add-JiraIssueWorklog $c -Issue TEST-003 -TimeSpent 60 -DateStarted (Get-Date) This example illustrates adding a comment based on other logic to a JIRA issue. Note the use of Format-Jira to convert the output of Get-Process into a format that is easily read by users. .INPUTS This function can accept PSJira.Issue objects via pipeline. @@ -45,7 +45,7 @@ function Add-JiraIssueWorklog Position = 2, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] - [String] $TimeSpent, + [Int] $TimeSpent, # Date/time started to be logged [Parameter(Mandatory = $true, From 0eb1c6c8ae448475f1b42e5e86c5e9a21ee58f62 Mon Sep 17 00:00:00 2001 From: padgers Date: Tue, 2 May 2017 18:42:48 +0100 Subject: [PATCH 033/102] Update Invoke-JiraIssueTransition.ps1 Add support for fields, comment and assignee parameters to Invoke-JiraIssueTransition. #38 --- PSJira/Public/Invoke-JiraIssueTransition.ps1 | 114 ++++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/PSJira/Public/Invoke-JiraIssueTransition.ps1 b/PSJira/Public/Invoke-JiraIssueTransition.ps1 index 34480ae5..d920fedb 100644 --- a/PSJira/Public/Invoke-JiraIssueTransition.ps1 +++ b/PSJira/Public/Invoke-JiraIssueTransition.ps1 @@ -16,6 +16,16 @@ function Invoke-JiraIssueTransition .EXAMPLE Invoke-JiraIssueTransition -Issue TEST-01 -Transition 11 Invokes transition ID 11 on issue TEST-01. + .EXAMPLE + Invoke-JiraIssueTransition -Issue TEST-01 -Transition 11 -Comment 'Transition comment' + Invokes transition ID 11 on issue TEST-01 with a comment. Requires the comment field to be configured visible for transition. + .EXAMPLE + Invoke-JiraIssueTransition -Issue TEST-01 -Transition 11 -Assignee 'joe.bloggs' + Invokes transition ID 11 on issue TEST-01 and assigns to user 'Joe Blogs'. Requires the assignee field to be configured as visible for transition. + .EXAMPLE + $transitionFields = @{'customfield_12345' = 'example'} + Invoke-JiraIssueTransition -Issue TEST-01 -Transition 11 -Fields $transitionFields + Invokes transition ID 11 on issue TEST-01 and configures a custom field value. Requires fields to be configured as visible for transition. .EXAMPLE $transition = Get-JiraIssue -Issue TEST-01 | Select-Object -ExpandProperty Transition | ? {$_.ResultStatus.Name -eq 'In Progress'} Invoke-JiraIssueTransition -Issue TEST-01 -Transition $transition @@ -40,6 +50,17 @@ function Invoke-JiraIssueTransition Position = 1)] [Object] $Transition, + # Any additional fields that should be updated. Fields must be configured to appear on the transition screen to use this parameter. + [System.Collections.Hashtable] $Fields, + + # New assignee of the issue. Enter 'Unassigned' to unassign the issue. Assignee field must be configured to appear on the transition screen to use this parameter. + [Parameter(Mandatory = $false)] + [Object] $Assignee, + + # Comment that should be added to JIRA. Comment field must be configured to appear on the transition screen to use this parameter. + [Parameter(Mandatory = $false)] + [String] $Comment, + # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential @@ -95,7 +116,96 @@ function Invoke-JiraIssueTransition 'id' = $transitionId; } } - $json = ConvertTo-Json -InputObject $props -Depth 3 + + if ($Assignee) + { + Write-Debug "[Invoke-JiraIssueTransition] Testing Assignee type" + if ($Assignee -eq 'Unassigned') + { + Write-Debug "[Invoke-JiraIssueTransition] 'Unassigned' String passed. Issue will be assigned to no one." + $assigneeString = "" + $validAssignee = $true + } else { + Write-Debug "[Invoke-JiraIssueTransition] Attempting to obtain Jira user [$Assignee]" + $assigneeObj = Get-JiraUser -InputObject $Assignee -Credential $Credential + if ($assigneeObj) + { + Write-Debug "[Invoke-JiraIssueTransition] User found (name=[$($assigneeObj.Name)],RestUrl=[$($assigneeObj.RestUrl)])" + $assigneeString = $assigneeObj.Name + $validAssignee = $true + } else { + Write-Debug "[Invoke-JiraIssueTransition] Unable to obtain Assignee. Exception will be thrown." + throw "Unable to validate Jira user [$Assignee]. Use Get-JiraUser for more details." + } + } + } + + + if ($validAssignee) + { + Write-Debug "[Invoke-JiraIssueTransition] Updating Assignee" + $props += @{ + 'fields' = @{ + 'assignee' = @{ + 'name' = $assigneeString; + } + } + } + } + + + if ($Fields) + { + Write-Debug "[Invoke-JiraIssueTransition] Validating field names" + $props += @{ + 'update' = @{} + } + + foreach ($k in $Fields.Keys) + { + $name = $k + $value = $Fields.$k + Write-Debug "[Invoke-JiraIssueTransition] Attempting to identify field (name=[$name], value=[$value])" + + $f = Get-JiraField -Field $name -Credential $Credential + if ($f) + { + # For some reason, this was coming through as a hashtable instead of a String, + # which was causing ConvertTo-Json to crash later. + # Not sure why, but this forces $id to be a String and not a hashtable. + $id = "$($f.ID)" + Write-Debug "[Invoke-JiraIssueTransition] Field [$name] was identified as ID [$id]" + $props.update.$id = @() + $props.update.$id += @{ + 'set' = $value; + } + } else { + Write-Debug "[Invoke-JiraIssueTransition] Field [$name] could not be identified in Jira" + throw "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." + } + } + } + + + if ($Comment) + { + Write-Debug "[Invoke-JiraIssueTransition] Adding comment" + if (-not $Fields) + { + Write-Debug "[Invoke-JiraIssueTransition] Create 'update' hashtable since not already created" + $props += @{ + 'update' = @{} + } + } + + $props.update.comment += ,@{ + 'add' = @{ + 'body' = $Comment + } + } + } + + $json = ConvertTo-Json -InputObject $props -Depth 4 Write-Debug "[Invoke-JiraIssueTransition] Converted properties to JSON" Write-Debug "[Invoke-JiraIssueTransition] Preparing for blastoff!" @@ -118,5 +228,3 @@ function Invoke-JiraIssueTransition Write-Debug "Complete" } } - - From 18785a888ab3bfdef4e7669de5c61ebded212d2b Mon Sep 17 00:00:00 2001 From: padgers Date: Tue, 2 May 2017 18:44:34 +0100 Subject: [PATCH 034/102] Update Invoke-JiraIssueTransition.Tests.ps1 Add new tests for fields, assignee and comment parameters to Invoke-JiraIssueTransition. #38 --- .../Invoke-JiraIssueTransition.Tests.ps1 | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/PSJira/Public/Invoke-JiraIssueTransition.Tests.ps1 b/PSJira/Public/Invoke-JiraIssueTransition.Tests.ps1 index 69634d90..f72d449f 100644 --- a/PSJira/Public/Invoke-JiraIssueTransition.Tests.ps1 +++ b/PSJira/Public/Invoke-JiraIssueTransition.Tests.ps1 @@ -85,7 +85,39 @@ InModuleScope PSJira { Assert-MockCalled Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It Assert-MockCalled Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It } - } -} + It "Updates custom fields if provided to the -Fields parameter" { + Mock Get-JiraField { + [PSCustomObject] @{ + 'Name' = $Field; + 'ID' = $Field; + } + } + { Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Fields @{'customfield_12345'='foo'; 'customfield_67890'='bar'} } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*customfield_12345*set*foo*' } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*customfield_67890*set*bar*' } + } + + It "Updates assignee name if provided to the -Assignee parameter"{ + Mock Get-JiraUser { + [PSCustomObject] @{ + 'Name' = 'powershell-user'; + 'RestUrl' = "$jiraServer/rest/api/2/user?username=powershell-user"; + } + } + { $result = Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Assignee 'powershell-user'} | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*name*powershell-user*' } + } + + It "Unassigns an issue if 'Unassigned' is passed to the -Assignee parameter"{ + { $result = Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Assignee 'Unassigned'} | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*name*""*' } + } + + It "Adds a comment if provide to the -Comment parameter"{ + { $result = Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Comment 'test comment'} | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*body*test comment*' } + } + } +} From e8cc4ee8b6f2204d550427784c12f8d851d157fa Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 09:28:07 +0200 Subject: [PATCH 035/102] [fix] Unit Tests have been updated to new schema --- .../ConvertTo-JiraLink.Tests.ps1 | 15 ++------ .../Get-JiraRemoteLink.Tests.ps1 | 35 ++++++++----------- .../Remove-JiraRemoteLink.Tests.ps1 | 4 +-- 3 files changed, 19 insertions(+), 35 deletions(-) rename {PSJira/Internal => Tests}/ConvertTo-JiraLink.Tests.ps1 (74%) rename {PSJira/Public => Tests}/Get-JiraRemoteLink.Tests.ps1 (74%) rename {PSJira/Public => Tests}/Remove-JiraRemoteLink.Tests.ps1 (96%) diff --git a/PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 b/Tests/ConvertTo-JiraLink.Tests.ps1 similarity index 74% rename from PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 rename to Tests/ConvertTo-JiraLink.Tests.ps1 index d66fae11..7305e38b 100644 --- a/PSJira/Internal/ConvertTo-JiraLink.Tests.ps1 +++ b/Tests/ConvertTo-JiraLink.Tests.ps1 @@ -1,15 +1,8 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { Describe "ConvertTo-JiraLink" { - function defProp($obj, $propName, $propValue) - { - It "Defines the '$propName' property" { - $obj.$propName | Should Be $propValue - } - } + . $PSScriptRoot\Shared.ps1 $jiraServer = 'http://jiraserver.example.com' $LinkID = "10000" @@ -51,9 +44,7 @@ InModuleScope PSJira { $r | Should Not BeNullOrEmpty } - It "Sets the type name to PSJira.Link" { - (Get-Member -InputObject $r).TypeName | Should Be 'PSJira.Link' - } + checkPsType $r 'PSJira.Link' defProp $r 'id' $LinkId defProp $r 'RestUrl' "$jiraServer/rest/api/issue/MKY-1/remotelink/10000" diff --git a/PSJira/Public/Get-JiraRemoteLink.Tests.ps1 b/Tests/Get-JiraRemoteLink.Tests.ps1 similarity index 74% rename from PSJira/Public/Get-JiraRemoteLink.Tests.ps1 rename to Tests/Get-JiraRemoteLink.Tests.ps1 index e2759777..e4cfee7a 100644 --- a/PSJira/Public/Get-JiraRemoteLink.Tests.ps1 +++ b/Tests/Get-JiraRemoteLink.Tests.ps1 @@ -1,14 +1,14 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { - - $showMockData = $false + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 $jiraServer = 'http://jiraserver.example.com' - $testIssueKey = 'MKY-1' + $issueKey = 'MKY-1' $restResult = @" { @@ -40,15 +40,14 @@ InModuleScope PSJira { Mock Get-JiraIssue { [PSCustomObject] @{ - 'RestURL' = 'https://jira.example.com/rest/api/2/issue/12345' - 'Key' = $testIssueKey + 'RestURL' = "$jiraServer/rest/api/2/issue/12345" + 'Key' = $issueKey } } # Searching for a group. Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get'} { - if ($ShowMockData) - { + if ($ShowMockData) { Write-Host " Mocked Invoke-JiraMethod with GET method" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan Write-Host " [URI] $URI" -ForegroundColor Cyan @@ -64,26 +63,22 @@ InModuleScope PSJira { throw "Unidentified call to Invoke-JiraMethod" } -# Mock Write-Debug { -# Write-Host "DEBUG: $Message" -ForegroundColor Yellow -# } - ############# # Tests ############# It "Gets information of all remote link from a Jira issue" { - $getResult = Get-JiraRemoteLink -Issue $testIssueKey + $getResult = Get-JiraRemoteLink -Issue $issueKey $getResult | Should Not BeNullOrEmpty } - It "Converts the output object to PSJira.Link" { - $getResult = Get-JiraRemoteLink -Issue $testIssueKey - (Get-Member -InputObject $getResult).TypeName | Should Be 'PSJira.Link' - } + # It "Converts the output object to PSJira.Link" { + # $getResult = Get-JiraRemoteLink -Issue $issueKey + # (Get-Member -InputObject $getResult).TypeName | Should Be 'PSJira.Link' + # } It "Returns all available properties about the returned link object" { - $getResult = Get-JiraRemoteLink -Issue $testIssueKey + $getResult = Get-JiraRemoteLink -Issue $issueKey $restObj = ConvertFrom-Json2 -InputObject $restResult $getResult.RestUrl | Should Be $restObj.self diff --git a/PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 b/Tests/Remove-JiraRemoteLink.Tests.ps1 similarity index 96% rename from PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 rename to Tests/Remove-JiraRemoteLink.Tests.ps1 index 64600359..fb148077 100644 --- a/PSJira/Public/Remove-JiraRemoteLink.Tests.ps1 +++ b/Tests/Remove-JiraRemoteLink.Tests.ps1 @@ -1,6 +1,4 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { From b0618d2f28258ff1c57accca81d299738b34cd17 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 09:28:57 +0200 Subject: [PATCH 036/102] removed type check in Get function --- Tests/Get-JiraRemoteLink.Tests.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tests/Get-JiraRemoteLink.Tests.ps1 b/Tests/Get-JiraRemoteLink.Tests.ps1 index e4cfee7a..4ee101bb 100644 --- a/Tests/Get-JiraRemoteLink.Tests.ps1 +++ b/Tests/Get-JiraRemoteLink.Tests.ps1 @@ -72,11 +72,6 @@ InModuleScope PSJira { $getResult | Should Not BeNullOrEmpty } - # It "Converts the output object to PSJira.Link" { - # $getResult = Get-JiraRemoteLink -Issue $issueKey - # (Get-Member -InputObject $getResult).TypeName | Should Be 'PSJira.Link' - # } - It "Returns all available properties about the returned link object" { $getResult = Get-JiraRemoteLink -Issue $issueKey $restObj = ConvertFrom-Json2 -InputObject $restResult From 38acaf4618daf5cc5eb34295eb71859f14820ca2 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 09:47:21 +0200 Subject: [PATCH 037/102] [fix] added empty line at end of file --- PSJira/Public/New-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index 937dab48..29f7cdc3 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -196,4 +196,4 @@ function New-JiraIssue { Write-Debug "[New-JiraIssue] Completing New-JiraIssue" } -} \ No newline at end of file +} From 53a311d4e4cb2430520db2eed45d2ef300162adf Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 10:36:02 +0200 Subject: [PATCH 038/102] trigger CI --- PSJira/Public/Get-JiraComponent.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index ca36552a..ff18937d 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -66,7 +66,7 @@ function Get-JiraComponent if ($Project) { if ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project') { - $ComponentId = @($Project.Components | select -ExpandProperty id) + $ComponentId = @($Project.Components | Select-Object -ExpandProperty id) } else { foreach ($p in $Project) { From dff63fbe386392f01b85338a6958c8d5e004e633 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 16:45:15 +0200 Subject: [PATCH 039/102] [added] Tests to ensure the cmdlets have a basic help --- Tests/PSJira.Help.Tests.ps1 | 227 ++++++++++++++++++++++++++++++++++++ Tests/PSJira.Tests.ps1 | 2 - 2 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 Tests/PSJira.Help.Tests.ps1 diff --git a/Tests/PSJira.Help.Tests.ps1 b/Tests/PSJira.Help.Tests.ps1 new file mode 100644 index 00000000..bcfeb882 --- /dev/null +++ b/Tests/PSJira.Help.Tests.ps1 @@ -0,0 +1,227 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.119 + Created on: 4/12/2016 1:11 PM + Created by: June Blender + Organization: SAPIEN Technologies, Inc + Filename: *.Help.Tests.ps1 + =========================================================================== + .DESCRIPTION + To test help for the commands in a module, place this file in the module folder. + To test any module from any path, use https://github.com/juneb/PesterTDD/Module.Help.Tests.ps1 +#> + +<# +.SYNOPSIS +Gets command parameters; one per name. Prefers default parameter set. + +.DESCRIPTION +Gets one CommandParameterInfo object for each parameter in the specified +command. If a command has more than one parameter with the same name, this +function gets the parameters in the default parameter set, if one is specified. + +For example, if a command has two parameter sets: + Name, ID (default) + Name, Path +This function returns: + Name (default), ID Path + +This function is used to get parameters for help and for help testing. + +.PARAMETER Command +Enter a CommandInfo object, such as the object that Get-Command returns. You +can also pipe a CommandInfo object to the function. + +This parameter takes a CommandInfo object, instead of a command name, so +you can use the parameters of Get-Command to specify the module and version +of the command. + +.EXAMPLE +PS C:\> Get-ParametersDefaultFirst -Command (Get-Command New-Guid) +This command uses the Command parameter to specify the command to +Get-ParametersDefaultFirst + +.EXAMPLE +PS C:\> Get-Command New-Guid | Get-ParametersDefaultFirst +You can also pipe a CommandInfo object to Get-ParametersDefaultFirst + +.EXAMPLE +PS C:\> Get-ParametersDefaultFirst -Command (Get-Command BetterCredentials\Get-Credential) +You can use the Command parameter to specify the CommandInfo object. This +command runs Get-Command module-qualified name value. + +.EXAMPLE +PS C:\> $ModuleSpec = @{ModuleName='BetterCredentials';RequiredVersion=4.3} +PS C:\> Get-Command -FullyQualifiedName $ModuleSpec | Get-ParametersDefaultFirst +This command uses a Microsoft.PowerShell.Commands.ModuleSpecification object to +specify the module and version. You can also use it to specify the module GUID. +Then, it pipes the CommandInfo object to Get-ParametersDefaultFirst. +#> +function Get-ParametersDefaultFirst +{ + param + ( + [Parameter(Mandatory = $true, + ValueFromPipeline = $true)] + [System.Management.Automation.CommandInfo] + $Command + ) + + BEGIN + { + $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' + $parameters = @() + } + PROCESS + { + if ($defaultPSetName = $Command.DefaultParameterSet) + { + $defaultParameters = ($Command.ParameterSets | Where-Object Name -eq $defaultPSetName).parameters | Where-Object Name -NotIn $common + $otherParameters = ($Command.ParameterSets | Where-Object Name -ne $defaultPSetName).parameters | Where-Object Name -NotIn $common + + $parameters += $defaultParameters + if ($parameters -and $otherParameters) + { + $otherParameters | ForEach-Object { + if ($_.Name -notin $parameters.Name) + { + $parameters += $_ + } + } + $parameters = $parameters | Sort-Object Name + } + } + else + { + $parameters = $Command.ParameterSets.Parameters | Where-Object Name -NotIn $common | Sort-Object Name -Unique + } + + + return $parameters + } + END { } +} + +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$projectRoot = Split-Path -Parent $here +$moduleRoot = "$projectRoot\PSJira" + + +# For tests in .\Tests subdirectory +if ((Split-Path $moduleRoot -Leaf) -eq 'Tests') +{ + $moduleRoot = Split-Path $moduleRoot -Parent +} + + +# Handles modules in version directories +$leaf = Split-Path $moduleRoot -Leaf +$parent = Split-Path $moduleRoot -Parent +$parsedVersion = $null +if ([System.Version]::TryParse($leaf, [ref]$parsedVersion)) +{ + $ModuleName = Split-Path $parent -Leaf +} +else +{ + $ModuleName = $leaf +} + +# Removes all versions of the module from the session before importing +Get-Module $ModuleName | Remove-Module + +# Because ModuleBase includes version number, this imports the required version +# of the module +$Module = Import-Module $moduleRoot\$ModuleName.psd1 -PassThru -ErrorAction Stop +$commands = Get-Command -Module $module -CommandType Cmdlet, Function, Workflow # Not alias + + +## When testing help, remember that help is cached at the beginning of each session. +## To test, restart session. + +foreach ($command in $commands) +{ + $commandName = $command.Name + + # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets + $Help = Get-Help $commandName -ErrorAction SilentlyContinue + + Describe "Test help for $commandName" -Tag "CommandHelp" { + + # If help is not found, synopsis in auto-generated help is the syntax diagram + It "should not be auto-generated" { + $Help.Synopsis | Should Not BeLike '*`[``]*' + } + + # Should be a synopsis for every function + It "gets synopsis for $commandName" { + $Help.Synopsis | Should Not beNullOrEmpty + } + + # Should be a description for every function + It "gets description for $commandName" { + $Help.Description | Should Not BeNullOrEmpty + } + + # Should be at least one example + It "gets example code from $commandName" { + ($Help.Examples.Example | Select-Object -First 1).Code | Should Not BeNullOrEmpty + } + + # Should be at least one example description + It "gets example help from $commandName" { + ($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should Not BeNullOrEmpty + } + + It "has at least as many examples as ParameterSets" { + ($Help.Examples.Example | Measure-Object).Count | Should Not BeLessThan $command.ParameterSets.Count + } + + Context "Test parameter help for $commandName" { + + $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', + 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' + + # Get parameters. When >1 parameter with same name, + # get parameter from the default parameter set, if any. + $parameters = Get-ParametersDefaultFirst -Command $command + + $parameterNames = $parameters.Name + $HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique + + foreach ($parameter in $parameters) { + $parameterName = $parameter.Name + $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName + + # Should be a description for every parameter + If ($parameterName -notmatch 'Confirm|WhatIf') { + It "gets help for parameter: $parameterName : in $commandName" { + $parameterHelp.Description.Text | Should Not BeNullOrEmpty + } + } + + # Required value in Help should match IsMandatory property of parameter + It "help for $parameterName parameter in $commandName has correct Mandatory value" { + $codeMandatory = $parameter.IsMandatory.toString() + $parameterHelp.Required | Should Be $codeMandatory + } + + # Parameter type in Help should match code + It "help for $commandName has correct parameter type for $parameterName" { + $codeType = $parameter.ParameterType.Name + # To avoid calling Trim method on a null object. + $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } + $helpType | Should be $codeType + } + } + + foreach ($helpParm in $HelpParameterNames) { + # Shouldn't find extra parameters in help. + It "finds help parameter in code: $helpParm" { + $helpParm -in $parameterNames | Should Be $true + } + } + } + } +} diff --git a/Tests/PSJira.Tests.ps1 b/Tests/PSJira.Tests.ps1 index daa1e4ab..5b3c867f 100644 --- a/Tests/PSJira.Tests.ps1 +++ b/Tests/PSJira.Tests.ps1 @@ -182,5 +182,3 @@ Describe "PSJira" { } } } - - From 6746cb332968d0f1e5376694e825fc915fc4b7b6 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 16:45:55 +0200 Subject: [PATCH 040/102] [fix] updated cmdlet's help - still has 17 fails --- PSJira/Public/Add-JiraGroupMember.ps1 | 76 ++++++------ PSJira/Public/Add-JiraIssueComment.ps1 | 7 +- PSJira/Public/Format-Jira.ps1 | 2 +- PSJira/Public/Get-JiraComponent.ps1 | 7 +- PSJira/Public/Get-JiraField.ps1 | 5 +- PSJira/Public/Get-JiraFilter.ps1 | 57 +++++---- PSJira/Public/Get-JiraGroup.ps1 | 6 +- PSJira/Public/Get-JiraGroupMember.ps1 | 63 +++++----- PSJira/Public/Get-JiraIssue.ps1 | 108 +++++++++--------- PSJira/Public/Get-JiraIssueComment.ps1 | 15 +-- PSJira/Public/Get-JiraIssueCreateMetadata.ps1 | 8 +- PSJira/Public/Get-JiraIssueEditMetadata.ps1 | 8 +- PSJira/Public/Get-JiraIssueType.ps1 | 5 +- PSJira/Public/Get-JiraPriority.ps1 | 5 +- PSJira/Public/Get-JiraProject.ps1 | 7 +- PSJira/Public/Get-JiraRemoteLink.ps1 | 35 +++--- PSJira/Public/Get-JiraUser.ps1 | 4 +- PSJira/Public/Invoke-JiraIssueTransition.ps1 | 49 ++++---- PSJira/Public/New-JiraGroup.ps1 | 25 ++-- PSJira/Public/New-JiraIssue.ps1 | 85 +++++++------- PSJira/Public/New-JiraSession.ps1 | 2 +- PSJira/Public/New-JiraUser.ps1 | 42 +++---- PSJira/Public/Remove-JiraGroup.ps1 | 43 +++---- PSJira/Public/Remove-JiraGroupMember.ps1 | 61 +++++----- PSJira/Public/Remove-JiraRemoteLink.ps1 | 10 +- PSJira/Public/Remove-JiraUser.ps1 | 43 +++---- PSJira/Public/Set-JiraConfigServer.ps1 | 1 + PSJira/Public/Set-JiraIssue.ps1 | 13 ++- PSJira/Public/Set-JiraIssueLabel.ps1 | 72 ++++++------ PSJira/Public/Set-JiraUser.ps1 | 9 +- 30 files changed, 433 insertions(+), 440 deletions(-) diff --git a/PSJira/Public/Add-JiraGroupMember.ps1 b/PSJira/Public/Add-JiraGroupMember.ps1 index c6dbb985..285397f9 100644 --- a/PSJira/Public/Add-JiraGroupMember.ps1 +++ b/PSJira/Public/Add-JiraGroupMember.ps1 @@ -1,5 +1,4 @@ -function Add-JiraGroupMember -{ +function Add-JiraGroupMember { <# .Synopsis Adds a user to a JIRA group @@ -25,29 +24,30 @@ function Add-JiraGroupMember #> [CmdletBinding()] param( + # Group (or list of groups) to which the user(s) will be added. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true)] + Position = 0, + ValueFromPipeline = $true)] [Alias('GroupName')] [Object[]] $Group, - # Username or user object obtained from Get-JiraUser + # Username or user object obtained from Get-JiraUser. [Parameter(Mandatory = $true)] [Alias('UserName')] [Object[]] $User, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential, - # Whether output should be provided after invoking this function + # Whether output should be provided after invoking this function. [Switch] $PassThru ) - begin - { + begin { Write-Debug "[Add-JiraGroupMember] Reading information from config file" - try - { + try { Write-Debug "[Add-JiraGroupMember] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { @@ -65,82 +65,76 @@ function Add-JiraGroupMember # request, which we'll loop through again in the Process block. $userAL = New-Object -TypeName System.Collections.ArrayList - foreach ($u in $User) - { + foreach ($u in $User) { Write-Debug "[Add-JiraGroupMember] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) - { + if ($userObj) { Write-Debug "[Add-JiraGroupMember] Retrieved user reference [$userObj]" -# $thisUserJson = ConvertTo-Json -InputObject @{ -# 'name' = $userObj.Name; -# } -# [void] $userAL.Add($thisUserJson) + # $thisUserJson = ConvertTo-Json -InputObject @{ + # 'name' = $userObj.Name; + # } + # [void] $userAL.Add($thisUserJson) [void] $userAL.Add($userObj.Name) - } else { + } + else { Write-Debug "[Add-JiraGroupMember] Could not identify user [$u]. Writing error message." Write-Error "Unable to identify user [$u]. Check the spelling of this user and ensure that you can access it via Get-JiraUser." } } -# $userJsons = $userAL.ToArray() + # $userJsons = $userAL.ToArray() $userNames = $userAL.ToArray() $restUrl = "$server/rest/api/latest/group/user?groupname={0}" } - process - { - foreach ($g in $Group) - { + process { + foreach ($g in $Group) { Write-Debug "[Add-JiraGroupMember] Obtaining reference to group [$g]" $groupObj = Get-JiraGroup -InputObject $g -Credential $Credential - if ($groupObj) - { + if ($groupObj) { Write-Debug "[Add-JiraGroupMember] Obtaining members of group [$g]" $groupMembers = Get-JiraGroupMember -Group $g -Credential $Credential | Select-Object -ExpandProperty Name $thisRestUrl = $restUrl -f $groupObj.Name Write-Debug "[Add-JiraGroupMember] Group URL: [$thisRestUrl]" -# foreach ($json in $userJsons) -# { -# Write-Debug "[Add-JiraGroupMember] Preparing for blastoff!" -# $result = Invoke-JiraMethod -Method Post -URI $thisRestUrl -Body $json -Credential $Credential -# } - foreach ($u in $userNames) - { - if ($groupMembers -notcontains $u) - { + # foreach ($json in $userJsons) + # { + # Write-Debug "[Add-JiraGroupMember] Preparing for blastoff!" + # $result = Invoke-JiraMethod -Method Post -URI $thisRestUrl -Body $json -Credential $Credential + # } + foreach ($u in $userNames) { + if ($groupMembers -notcontains $u) { Write-Debug "[Add-JiraGroupMember] User [$u] is not already in group [$g]. Adding user." $userJson = ConvertTo-Json -InputObject @{ 'name' = $u; } Write-Debug "[Add-JiraGroupMember] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $thisRestUrl -Body $userJson -Credential $Credential - } else { + } + else { Write-Debug "[Add-JiraGroupMember] User [$u] is already a member of group [$g]" Write-Verbose "User [$u] is already a member of group [$g]" } } - if ($PassThru) - { + if ($PassThru) { Write-Debug "[Add-JiraGroupMember] -PassThru specified. Obtaining a final reference to group [$g]" $groupObjNew = Get-JiraGroup -InputObject $g -Credential $Credential Write-Debug "[Add-JiraGroupMember] Outputting group [$groupObjNew]" Write-Output $groupObjNew } - } else { + } + else { Write-Debug "[Add-JiraGroupMember] Could not identify group [$g]" Write-Error "Unable to identify group [$g]. Check the spelling of this group and ensure that you can access it via Get-JiraGroup." } } } - end - { + end { Write-Debug "[Add-JiraGroupMember] Complete" } } diff --git a/PSJira/Public/Add-JiraIssueComment.ps1 b/PSJira/Public/Add-JiraIssueComment.ps1 index efb36f23..3c6659e9 100644 --- a/PSJira/Public/Add-JiraIssueComment.ps1 +++ b/PSJira/Public/Add-JiraIssueComment.ps1 @@ -27,12 +27,12 @@ function Add-JiraIssueComment #> [CmdletBinding()] param( - # Comment that should be added to JIRA + # Comment that should be added to JIRA. [Parameter(Mandatory = $true, Position = 0)] [String] $Comment, - # Issue that should be commented upon + # Issue that should be commented upon. [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, @@ -44,7 +44,8 @@ function Add-JiraIssueComment [ValidateSet('All Users','Developers','Administrators')] [String] $VisibleRole = 'Developers', - # Credentials to use to connect to Jira. If not specified, this function will use + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Format-Jira.ps1 b/PSJira/Public/Format-Jira.ps1 index e4564fe8..10c0cca0 100644 --- a/PSJira/Public/Format-Jira.ps1 +++ b/PSJira/Public/Format-Jira.ps1 @@ -30,7 +30,7 @@ function Format-Jira Position = 0)] [Object[]] $Property, - # Object to format + # Object to format. [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromRemainingArguments = $true)] diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index ff18937d..bee86a7c 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -28,20 +28,21 @@ function Get-JiraComponent #> [CmdletBinding(DefaultParameterSetName = 'ByID')] param( - # The Project ID or project key of a project to search + # The Project ID or project key of a project to search. [Parameter(ParameterSetName = 'ByProject', ValueFromPipeline, Mandatory = $true)] $Project, - # The Component ID + # The Component ID. [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'ByID')] [Alias("Id")] [int[]] $ComponentId, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraField.ps1 b/PSJira/Public/Get-JiraField.ps1 index 475b2e5a..c23b0f0f 100644 --- a/PSJira/Public/Get-JiraField.ps1 +++ b/PSJira/Public/Get-JiraField.ps1 @@ -22,13 +22,14 @@ #> [CmdletBinding()] param( - # The Field name or ID to search + # The Field name or ID to search. [Parameter(Mandatory = $false, Position = 0, ValueFromRemainingArguments = $true)] [String[]] $Field, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraFilter.ps1 b/PSJira/Public/Get-JiraFilter.ps1 index d2fe0af8..573f8b0f 100644 --- a/PSJira/Public/Get-JiraFilter.ps1 +++ b/PSJira/Public/Get-JiraFilter.ps1 @@ -1,5 +1,4 @@ -function Get-JiraFilter -{ +function Get-JiraFilter { <# .Synopsis Returns information about a filter in JIRA @@ -10,6 +9,9 @@ .EXAMPLE Get-JiraFilter -Id 12345 Gets a reference to filter ID 12345 from JIRA + .EXAMPLE + $filterObject | Get-JiraFilter + Gets the information of a filter by providing a filter object .INPUTS [Object[]] The filter to look up in JIRA. This can be a String (filter ID) or a PSJira.Filter object. .OUTPUTS @@ -17,27 +19,28 @@ #> [CmdletBinding(DefaultParameterSetName = 'ByFilterID')] param( + # ID of the filter to search for. [Parameter(ParameterSetName = 'ByFilterID', - Mandatory = $true, - Position = 0)] + Mandatory = $true, + Position = 0)] [String[]] $Id, + # Object of the filter to search for. [Parameter(ParameterSetName = 'ByInputObject', - Mandatory = $true, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Object[]] $InputObject, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) - begin - { + begin { Write-Debug "[Get-JiraFilter] Reading server from config file" - try - { + try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { $err = $_ @@ -48,39 +51,36 @@ $uri = "$server/rest/api/latest/filter/{0}" } - process - { - if ($PSCmdlet.ParameterSetName -eq 'ByFilterID') - { - foreach ($i in $Id) - { + process { + if ($PSCmdlet.ParameterSetName -eq 'ByFilterID') { + foreach ($i in $Id) { Write-Debug "[Get-JiraFilter] Processing filter [$i]" $thisUri = $uri -f $i Write-Debug "[Get-JiraFilter] Filter URI: [$thisUri]" Write-Debug "[Get-JiraFilter] Preparing for blast off!" $result = Invoke-JiraMethod -Method Get -URI $thisUri -Credential $Credential - if ($result) - { + if ($result) { Write-Debug "[Get-JiraFilter] Converting result to JiraFilter object" $obj = ConvertTo-JiraFilter -InputObject $result Write-Debug "Outputting result" Write-Output $obj - } else { + } + else { Write-Debug "[Get-JiraFilter] Invoke-JiraFilter returned no results to output." } } - } else { - foreach ($i in $InputObject) - { + } + else { + foreach ($i in $InputObject) { Write-Debug "[Get-JiraFilter] Processing InputObject [$i]" - if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Filter') - { + if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Filter') { Write-Debug "[Get-JiraFilter] User parameter is a PSJira.Filter object" $thisId = $i.ID - } else { + } + else { $thisId = $i.ToString() Write-Debug "[Get-JiraFilter] ID is assumed to be [$thisId] via ToString()" } @@ -93,8 +93,7 @@ } } - end - { + end { Write-Debug "[Get-JiraFilter] Complete" } } diff --git a/PSJira/Public/Get-JiraGroup.ps1 b/PSJira/Public/Get-JiraGroup.ps1 index ad18f478..b5b8def0 100644 --- a/PSJira/Public/Get-JiraGroup.ps1 +++ b/PSJira/Public/Get-JiraGroup.ps1 @@ -22,7 +22,7 @@ function Get-JiraGroup #> [CmdletBinding(DefaultParameterSetName = 'ByGroupName')] param( - # Name of the group + # Name of the group to search for. [Parameter(ParameterSetName = 'ByGroupName', Mandatory = $true, Position = 0)] @@ -30,6 +30,7 @@ function Get-JiraGroup [Alias('Name')] [String[]] $GroupName, + # Object of the group to search for. [Parameter(ParameterSetName = 'ByInputObject', Mandatory = $true, Position = 0, @@ -37,7 +38,8 @@ function Get-JiraGroup ValueFromPipelineByPropertyName = $true)] [Object[]] $InputObject, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraGroupMember.ps1 b/PSJira/Public/Get-JiraGroupMember.ps1 index 6f9b780e..0c5bf283 100644 --- a/PSJira/Public/Get-JiraGroupMember.ps1 +++ b/PSJira/Public/Get-JiraGroupMember.ps1 @@ -1,5 +1,4 @@ -function Get-JiraGroupMember -{ +function Get-JiraGroupMember { <# .Synopsis Returns members of a given group in JIRA @@ -29,10 +28,11 @@ function Get-JiraGroupMember #> [CmdletBinding()] param( + # Group object of which to display the members. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Object] $Group, # Index of the first user to return. This can be used to "page" through @@ -47,41 +47,36 @@ function Get-JiraGroupMember [ValidateRange(0, [Int]::MaxValue)] [Int] $MaxResults = 0, - # Credentials to use to connect to JIRA. If not specified, this function will use anonymous access. + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) - begin - { + begin { # This is a parameter in Get-JiraIssue, but in testing, JIRA doesn't # reliably return more than 50 results at a time. $pageSize = 50 - if ($MaxResults -eq 0) - { + if ($MaxResults -eq 0) { Write-Debug "[Get-JiraGroupMember] MaxResults was not specified. Using loop mode to obtain all members." $loopMode = $true - } else { + } + else { $loopMode = $false - if ($MaxResults -gt 50) - { + if ($MaxResults -gt 50) { Write-Warning "JIRA's API may not properly support MaxResults values higher than 50 for this method. If you receive inconsistent results, do not pass the MaxResults parameter to this function to return all results." } } } - process - { + process { Write-Debug "[Get-JiraGroupMember] Obtaining a reference to Jira group [$Group]" $groupObj = Get-JiraGroup -GroupName $Group -Credential $Credential - if ($groupObj) - { - foreach ($g in $groupObj) - { - if ($loopMode) - { + if ($groupObj) { + foreach ($g in $groupObj) { + if ($loopMode) { # Using the Size property of the group object, iterate # through all users in a given group. @@ -89,20 +84,18 @@ function Get-JiraGroupMember $allUsers = New-Object -TypeName System.Collections.ArrayList Write-Debug "[Get-JiraGroupMember] Paging through all results (loop mode)" - for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) - { - if ($PageSize -gt ($i + $totalResults)) - { + for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) { + if ($PageSize -gt ($i + $totalResults)) { $thisPageSize = $totalResults - $i - } else { + } + else { $thisPageSize = $PageSize } $percentComplete = ($i / $totalResults) * 100 Write-Progress -Activity 'Get-JiraGroupMember' -Status "Obtaining members ($i - $($i + $thisPageSize) of $totalResults)..." -PercentComplete $percentComplete Write-Debug "[Get-JiraGroupMember] Obtaining members $i - $($i + $thisPageSize)..." $thisSection = Get-JiraGroupMember -Group $g -StartIndex $i -MaxResults $thisPageSize -Credential $Credential - foreach ($t in $thisSection) - { + foreach ($t in $thisSection) { [void] $allUsers.Add($t) } } @@ -110,7 +103,8 @@ function Get-JiraGroupMember Write-Progress -Activity 'Get-JiraGroupMember' -Completed Write-Output ($allUsers.ToArray()) - } else { + } + else { # Since user is an expandable property of the returned # group from JIRA, JIRA doesn't use the MaxResults argument # found in other REST endpoints. Instead, we need to pass @@ -120,8 +114,7 @@ function Get-JiraGroupMember Write-Debug "[Get-JiraGroupMember] Preparing for blastoff!" $groupResult = Invoke-JiraMethod -Method Get -URI $url -Credential $Credential - if ($groupResult) - { + if ($groupResult) { # ConvertTo-JiraGroup contains logic to convert and add # users (group members) to user objects if the members # are returned from JIRA. @@ -131,17 +124,17 @@ function Get-JiraGroupMember Write-Debug "[Get-JiraGroupMember] Outputting group members" Write-Output $groupObjResult.Member - } else { + } + else { # Something is wrong here...we didn't get back a result from JIRA when we *did* get a # valid group from Get-JiraGroup earlier. Write-Warning "A JIRA group could not be found at URL [$url], even though this seems to be a valid group." } } } - } else { + } + else { throw "Unable to identify group [$Group]. Use Get-JiraGroup to make sure this is a valid JIRA group." } } } - - diff --git a/PSJira/Public/Get-JiraIssue.ps1 b/PSJira/Public/Get-JiraIssue.ps1 index 76a14087..30dd8f6d 100644 --- a/PSJira/Public/Get-JiraIssue.ps1 +++ b/PSJira/Public/Get-JiraIssue.ps1 @@ -1,5 +1,4 @@ -function Get-JiraIssue -{ +function Get-JiraIssue { <# .Synopsis Returns information about an issue in JIRA. @@ -33,29 +32,37 @@ function Get-JiraIssue #> [CmdletBinding(DefaultParameterSetName = 'ByIssueKey')] param( + # Key of the issue to search for. [Parameter(ParameterSetName = 'ByIssueKey', - Mandatory = $true, - Position = 0)] + Mandatory = $true, + Position = 0)] [ValidateNotNullOrEmpty()] [String[]] $Key, + # Object of an issue to search for. [Parameter(ParameterSetName = 'ByInputObject', - Mandatory = $true, - Position = 0)] + Mandatory = $true, + Position = 0)] [Object[]] $InputObject, + # JQL query for which to search for. [Parameter(ParameterSetName = 'ByJQL', - Mandatory = $true)] + Mandatory = $true)] [Alias('JQL')] [String] $Query, + # Object of an existing JIRA filter from which the results will be returned. [Parameter(ParameterSetName = 'ByFilter')] [Object] $Filter, + # Index of the first issue to return. This can be used to "page" through + # issues in a large collection or a slow connection. [Parameter(ParameterSetName = 'ByJQL')] [Parameter(ParameterSetName = 'ByFilter')] [Int] $StartIndex = 0, + # Maximum number of results to return. By default, all issues will be + # returned. [Parameter(ParameterSetName = 'ByJQL')] [Parameter(ParameterSetName = 'ByFilter')] [Int] $MaxResults = 0, @@ -68,13 +75,13 @@ function Get-JiraIssue [Parameter(ParameterSetName = 'ByFilter')] [Int] $PageSize = 50, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) - begin - { + begin { Write-Debug "[Get-JiraIssue] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop @@ -82,48 +89,45 @@ function Get-JiraIssue $psName = $PSCmdlet.ParameterSetName - if (($psName -eq 'ByJQL' -or $psName -eq 'ByFilter') -and $MaxResults -eq 0) - { + if (($psName -eq 'ByJQL' -or $psName -eq 'ByFilter') -and $MaxResults -eq 0) { Write-Debug "[Get-JiraIssue] Using loop mode to obtain all results" $MaxResults = 1 $loopMode = $true - } else { + } + else { $loopMode = $false } } - process - { - if ($PSCmdlet.ParameterSetName -eq 'ByIssueKey') - { - foreach ($k in $Key) - { + process { + if ($PSCmdlet.ParameterSetName -eq 'ByIssueKey') { + foreach ($k in $Key) { Write-Debug "[Get-JiraIssue] Processing issue key [$k]" $issueURL = "$($server)/rest/api/latest/issue/${k}?expand=transitions" Write-Debug "[Get-JiraIssue] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential - if ($result) - { + if ($result) { Write-Debug "[Get-JiraIssue] Converting REST result to Jira object" $obj = ConvertTo-JiraIssue -InputObject $result Write-Debug "[Get-JiraIssue] Outputting result" Write-Output $obj - } else { + } + else { Write-Debug "[Get-JiraIssue] Invoke-JiraMethod returned no results to output." } } - } elseif ($PSCmdlet.ParameterSetName -eq 'ByInputObject') { - foreach ($i in $InputObject) - { + } + elseif ($PSCmdlet.ParameterSetName -eq 'ByInputObject') { + foreach ($i in $InputObject) { Write-Debug "[Get-JiraIssue] Processing InputObject [$i]" - if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Issue') - { + if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Issue') { Write-Debug "[Get-JiraIssue] Issue parameter is a PSJira.Issue object" $issueKey = $i.Key - } else { + } + else { $issueKey = $i.ToString() Write-Debug "[Get-JiraIssue] Issue key is assumed to be [$issueKey] via ToString()" } @@ -133,7 +137,8 @@ function Get-JiraIssue Write-Debug "[Get-JiraIssue] Returned from invoking myself; outputting results" Write-Output $issueObj } - } elseif ($PSCmdlet.ParameterSetName -eq 'ByJQL') { + } + elseif ($PSCmdlet.ParameterSetName -eq 'ByJQL') { Write-Debug "[Get-JiraIssue] Escaping query and building URL" $escapedQuery = [System.Web.HttpUtility]::UrlPathEncode($Query) @@ -142,47 +147,46 @@ function Get-JiraIssue Write-Debug "[Get-JiraIssue] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential - if ($result) - { + if ($result) { # {"startAt":0,"maxResults":50,"total":0,"issues":[]} - if ($loopMode) - { + if ($loopMode) { $totalResults = $result.total Write-Debug "[Get-JiraIssue] Paging through all issues (loop mode)" $allIssues = New-Object -TypeName System.Collections.ArrayList - for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) - { + for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) { $percentComplete = ($i / $totalResults) * 100 Write-Progress -Activity 'Get-JiraIssue' -Status "Obtaining issues ($i - $($i + $PageSize))..." -PercentComplete $percentComplete Write-Debug "[Get-JiraIssue] Obtaining issues $i - $($i + $PageSize)..." $thisSection = Get-JiraIssue -Query $Query -StartIndex $i -MaxResults $PageSize -Credential $Credential - foreach ($t in $thisSection) - { + foreach ($t in $thisSection) { [void] $allIssues.Add($t) } } Write-Progress -Activity 'Get-JiraIssue' -Status 'Obtaining issues' -Completed Write-Output ($allIssues.ToArray()) - } elseif ($result.total -gt 0) { + } + elseif ($result.total -gt 0) { Write-Debug "[Get-JiraIssue] Converting REST result to Jira issue" $obj = ConvertTo-JiraIssue -InputObject $result.issues Write-Debug "[Get-JiraIssue] Outputting result" Write-Output $obj - } else { + } + else { Write-Debug "[Get-JiraIssue] No results were found for the specified query" Write-Verbose "No results were found for the query [$Query]" } - } else { + } + else { Write-Debug "[Get-JiraIssue] Invoke-JiraMethod returned no results" } - } elseif ($PSCmdlet.ParameterSetName -eq 'ByFilter') { + } + elseif ($PSCmdlet.ParameterSetName -eq 'ByFilter') { $filterObj = Get-JiraFilter -InputObject $Filter -Credential $Credential - if ($filterObj) - { + if ($filterObj) { $jql = $filterObj.JQL Write-Debug "[Get-JiraIssue] Invoking myself with filter JQL: [$jql]" @@ -190,28 +194,28 @@ function Get-JiraIssue # was not supplied as a parameter. We don't want to explicitly # invoke this method recursively with a MaxResults value of 1 # if it wasn't initially provided to us. - if ($loopMode) - { + if ($loopMode) { $result = Get-JiraIssue -Query $jql -Credential $Credential - } else { + } + else { $result = Get-JiraIssue -Query $jql -Credential $Credential -MaxResults $MaxResults } - if ($result) - { + if ($result) { Write-Debug "[Get-JiraIssue] Returned from invoking myself; outputting results" Write-Output $result - } else { + } + else { Write-Debug "[Get-JiraIssue] Returned from invoking myself, but no results were found" } - } else { + } + else { Write-Debug "[Get-JiraIssue] Unable to identify filter [$Filter]" Write-Error "Unable to identify filter [$Filter]. Check Get-JiraFilter for more details." } } } - end - { + end { Write-Debug "[Get-JiraIssue] Complete" } } diff --git a/PSJira/Public/Get-JiraIssueComment.ps1 b/PSJira/Public/Get-JiraIssueComment.ps1 index 56a84980..abf6cdf2 100644 --- a/PSJira/Public/Get-JiraIssueComment.ps1 +++ b/PSJira/Public/Get-JiraIssueComment.ps1 @@ -1,5 +1,4 @@ -function Get-JiraIssueComment -{ +function Get-JiraIssueComment { <# .Synopsis Returns comments on an issue in JIRA. @@ -20,15 +19,17 @@ function Get-JiraIssueComment #> [CmdletBinding()] param( - # JIRA issue to check for comments. Can be a PSJira.Issue object, issue key, or internal issue ID. + # JIRA issue to check for comments. + # Can be a PSJira.Issue object, issue key, or internal issue ID. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Alias('Key')] [Object] $Issue, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 b/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 index 4725a2f7..216b7642 100644 --- a/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 +++ b/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 @@ -22,19 +22,21 @@ function Get-JiraIssueCreateMetadata #> [CmdletBinding()] param( - # Project ID or key + # Project ID or key of the reference issue. [Parameter(Mandatory = $true, Position = 0)] [String] $Project, - # Issue type ID or name + # Issue type ID or name. [Parameter(Mandatory = $true, Position = 1)] [String] $IssueType, + # Path of the file with the configuration. [String] $ConfigFile, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 index 74d5d53b..0cfe992a 100644 --- a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 +++ b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 @@ -22,14 +22,16 @@ function Get-JiraIssueEditMetadata #> [CmdletBinding()] param( - # Issue id or key + # Issue id or key of the reference issue. [Parameter(Mandatory = $true, Position = 0)] [String] $Issue, + # Path of the file with the configuration. [String] $ConfigFile, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) @@ -92,5 +94,3 @@ function Get-JiraIssueEditMetadata } } } - - diff --git a/PSJira/Public/Get-JiraIssueType.ps1 b/PSJira/Public/Get-JiraIssueType.ps1 index c6ef86b8..450d38f8 100644 --- a/PSJira/Public/Get-JiraIssueType.ps1 +++ b/PSJira/Public/Get-JiraIssueType.ps1 @@ -2,13 +2,14 @@ { [CmdletBinding()] param( - # The Issue Type name or ID to search + # The Issue Type name or ID to search. [Parameter(Mandatory = $false, Position = 0, ValueFromRemainingArguments = $true)] [String[]] $IssueType, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraPriority.ps1 b/PSJira/Public/Get-JiraPriority.ps1 index a15a7764..835f9a6e 100644 --- a/PSJira/Public/Get-JiraPriority.ps1 +++ b/PSJira/Public/Get-JiraPriority.ps1 @@ -2,11 +2,12 @@ function Get-JiraPriority { [CmdletBinding()] param( - # ID of the priority to get + # ID of the priority to get. [Parameter(Mandatory = $false)] [Int] $Id, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Get-JiraProject.ps1 b/PSJira/Public/Get-JiraProject.ps1 index 7f2453fc..2b63c687 100644 --- a/PSJira/Public/Get-JiraProject.ps1 +++ b/PSJira/Public/Get-JiraProject.ps1 @@ -26,12 +26,13 @@ function Get-JiraProject #> [CmdletBinding(DefaultParameterSetName = 'AllProjects')] param( - # The Project ID or project key of a project to search + # The Project ID or project key of a project to search. [Parameter(Mandatory = $false, Position = 0)] [String[]] $Project, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) @@ -100,5 +101,3 @@ function Get-JiraProject Write-Debug "Complete" } } - - diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 index 080c6e18..096935c4 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -1,5 +1,4 @@ -function Get-JiraRemoteLink -{ +function Get-JiraRemoteLink { <# .Synopsis Returns a remote link from a Jira issue @@ -18,24 +17,25 @@ function Get-JiraRemoteLink #> [CmdletBinding()] param( + # The Issue Object or ID to link. [Parameter(ValueFromPipelineByPropertyName = $true, - ValueFromPipeline = $true, - Mandatory = $true, - Position = 0 + ValueFromPipeline = $true, + Mandatory = $true, + Position = 0 )] [Alias("Key")] [String[]]$Issue, - # Get a single link by it's id + # Get a single link by it's id. [Int]$LinkId, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential ) - Begin - { + Begin { Write-Debug "[Get-JiraRemoteLink] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop @@ -45,35 +45,32 @@ function Get-JiraRemoteLink $linkUrl = "$server/rest/api/latest/issue/{0}/remotelink" } - Process - { - foreach ($k in $Issue) - { + Process { + foreach ($k in $Issue) { Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" $thisUrl = $linkUrl -f $k if ($linkId) - { $thisUrl += "/$l" } + { $thisUrl += "/$l" } Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential - if ($result) - { + if ($result) { Write-Debug "[Get-JiraRemoteLink] Converting results to PSJira.Group" $obj = ConvertTo-JiraLink -InputObject $result Write-Debug "[Get-JiraRemoteLink] Outputting results" Write-Output $obj - } else { + } + else { Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" Write-Verbose "No results were returned from JIRA." } } } - End - { + End { Write-Debug "[Get-JiraRemoteLink] Complete" } } diff --git a/PSJira/Public/Get-JiraUser.ps1 b/PSJira/Public/Get-JiraUser.ps1 index cc7f0052..4e72120b 100644 --- a/PSJira/Public/Get-JiraUser.ps1 +++ b/PSJira/Public/Get-JiraUser.ps1 @@ -29,6 +29,7 @@ function Get-JiraUser [Alias('User','Name')] [String[]] $UserName, + # User Object of the user. [Parameter(ParameterSetName = 'ByInputObject', Mandatory = $true, Position = 0)] @@ -37,7 +38,8 @@ function Get-JiraUser # Include inactive users in the search [Switch] $IncludeInactive, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) diff --git a/PSJira/Public/Invoke-JiraIssueTransition.ps1 b/PSJira/Public/Invoke-JiraIssueTransition.ps1 index 34480ae5..2e304ed6 100644 --- a/PSJira/Public/Invoke-JiraIssueTransition.ps1 +++ b/PSJira/Public/Invoke-JiraIssueTransition.ps1 @@ -1,5 +1,4 @@ -function Invoke-JiraIssueTransition -{ +function Invoke-JiraIssueTransition { <# .Synopsis Performs an issue transition on a JIRA issue, changing its status @@ -29,47 +28,46 @@ function Invoke-JiraIssueTransition #> [CmdletBinding()] param( + # The Issue Object or ID to transition. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Alias('Key')] [Object] $Issue, + # The Transition Object or ID. [Parameter(Mandatory = $true, - Position = 1)] + Position = 1)] [Object] $Transition, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential ) - begin - { + begin { # We can't validate pipeline input here, since pipeline input doesn't exist in the Begin block. } - process - { + process { Write-Debug "[Invoke-JiraIssueTransition] Obtaining a reference to Jira issue [$Issue]" $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential - if (-not $issueObj) - { + if (-not $issueObj) { Write-Debug "[Invoke-JiraIssueTransition] No Jira issues were found for parameter [$Issue]. An exception will be thrown." throw "Unable to identify Jira issue [$Issue]. Use Get-JiraIssue for more information." } Write-Debug "[Invoke-JiraIssueTransition] Checking Transition parameter" - if ($Transition.PSObject.TypeNames[0] -eq 'PSJira.Transition') - { + if ($Transition.PSObject.TypeNames[0] -eq 'PSJira.Transition') { Write-Debug "[Invoke-JiraIssueTransition] Transition parameter is a PSJira.Transition object" $transitionId = $Transition.ID - } else { + } + else { Write-Debug "[Invoke-JiraIssueTransition] Attempting to cast Transition parameter [$Transition] as int for transition ID" - try - { + try { $transitionId = [int] "$Transition" } catch { $err = $_ @@ -79,10 +77,10 @@ function Invoke-JiraIssueTransition } Write-Debug "[Invoke-JiraIssueTransition] Checking that the issue can perform the given transition" - if (($issueObj.Transition | Select-Object -ExpandProperty ID) -contains $transitionId) - { + if (($issueObj.Transition | Select-Object -ExpandProperty ID) -contains $transitionId) { Write-Debug "[Invoke-JiraIssueTransition] Transition [$transitionId] is valid for issue [$issueObj]" - } else { + } + else { Write-Debug "[Invoke-JiraIssueTransition] Transition [$transitionId] is not valid for issue [$issueObj]. An exception will be thrown." throw "The specified Jira issue cannot perform transition [$transitionId]. Check the issue's Transition property and provide a transition valid for its current state." } @@ -101,20 +99,19 @@ function Invoke-JiraIssueTransition Write-Debug "[Invoke-JiraIssueTransition] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $transitionUrl -Body $json -Credential $Credential - if ($result) - { + if ($result) { # JIRA doesn't typically return results here unless they contain errors, which are handled within Invoke-JiraMethod. # If something does come out, let us know. Write-Debug "[Invoke-JiraIssueTransition] Outputting raw results from JIRA." Write-Warning "JIRA returned unexpected results, which are provided below." Write-Output $result - } else { + } + else { Write-Debug "[Invoke-JiraIssueTransition] No results were returned from JIRA." } } - end - { + end { Write-Debug "Complete" } } diff --git a/PSJira/Public/New-JiraGroup.ps1 b/PSJira/Public/New-JiraGroup.ps1 index d6f308af..f5574e92 100644 --- a/PSJira/Public/New-JiraGroup.ps1 +++ b/PSJira/Public/New-JiraGroup.ps1 @@ -1,5 +1,4 @@ -function New-JiraGroup -{ +function New-JiraGroup { <# .Synopsis Creates a new group in JIRA @@ -15,20 +14,21 @@ #> [CmdletBinding()] param( + # Name for the new group. [Parameter(Mandatory = $true, - Position = 0)] - [Alias('Group','Name')] + Position = 0)] + [Alias('Name')] [String] $GroupName, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential ) - begin - { + begin { Write-Debug "[New-JiraGroup] Reading information from config file" - try - { + try { Write-Debug "[New-JiraGroup] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { @@ -40,8 +40,7 @@ $restUrl = "$server/rest/api/latest/group" } - process - { + process { Write-Debug "[New-JiraGroup] Defining properties" $props = @{ "name" = $GroupName; @@ -53,11 +52,11 @@ Write-Debug "[New-JiraGroup] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $restUrl -Body $json -Credential $Credential - if ($result) - { + if ($result) { Write-Debug "[New-JiraGroup] Converting output object into a Jira user and outputting" ConvertTo-JiraGroup -InputObject $result - } else { + } + else { Write-Debug "[New-JiraGroup] Jira returned no results to output." } } diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index 29f7cdc3..ee205f68 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -1,5 +1,4 @@ -function New-JiraIssue -{ +function New-JiraIssue { <# .Synopsis Creates an issue in JIRA @@ -29,42 +28,52 @@ function New-JiraIssue #> [CmdletBinding()] param( + # Project in which to create the issue. [Parameter(Mandatory = $true)] [String] $Project, + # Type of the issue. [Parameter(Mandatory = $true)] [String] $IssueType, + # ID of the Priority the issue shall have. [Parameter(Mandatory = $false)] [Int] $Priority, + # Summary of the issue. [Parameter(Mandatory = $true)] [String] $Summary, + # Long description of the issue. [Parameter(Mandatory = $false)] [String] $Description, + # User that shall be registed as the reporter. + # If left empty, the currently authenticated user will be used. [Parameter(Mandatory = $false)] [String] $Reporter, + # List of labels which will be added to the issue. [Parameter(Mandatory = $false)] [String[]] $Labels, + # Parent issue - in case of "Sub-Tasks". [Parameter(Mandatory = $false)] [String] $Parent, + # Hashtable (dictionary) with other fields. [Parameter(Mandatory = $false)] [Hashtable] $Fields, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential ) - begin - { + begin { Write-Debug "[New-JiraIssue] Reading information from config file" - try - { + try { Write-Debug "[New-JiraIssue] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop @@ -80,31 +89,28 @@ function New-JiraIssue Write-Debug "[New-JiraIssue] Obtaining a reference to Jira project [$Project]" $ProjectObj = Get-JiraProject -Project $Project -Credential $Credential - if (-not ($ProjectObj)) - { + if (-not ($ProjectObj)) { throw "Unable to identify Jira project [$Project]. Use Get-JiraProject for more information." } Write-Debug "[New-JiraIssue] Obtaining a reference to Jira issue type [$IssueType]" $IssueTypeObj = Get-JiraIssueType -IssueType $IssueType -Credential $Credential - if (-not ($IssueTypeObj)) - { + if (-not ($IssueTypeObj)) { throw "Unable to identify Jira issue type [$IssueType]. Use Get-JiraIssueType for more information." } } - process - { - $ProjectParam = New-Object -TypeName PSObject -Property @{"id"=$ProjectObj.Id} - $IssueTypeParam = New-Object -TypeName PSObject -Property @{"id"=[String] $IssueTypeObj.Id} + process { + $ProjectParam = New-Object -TypeName PSObject -Property @{"id" = $ProjectObj.Id} + $IssueTypeParam = New-Object -TypeName PSObject -Property @{"id" = [String] $IssueTypeObj.Id} $props = @{ - "project"=$ProjectParam; - "summary"=$Summary; - "issuetype"=$IssueTypeParam; + "project" = $ProjectParam; + "summary" = $Summary; + "issuetype" = $IssueTypeParam; } if ($Priority) { - $props.priority = New-Object -TypeName PSObject -Property @{"id"=[String] $Priority} + $props.priority = New-Object -TypeName PSObject -Property @{"id" = [String] $Priority} } if ($Description) { @@ -112,11 +118,11 @@ function New-JiraIssue } if ($Reporter) { - $props.reporter = New-Object -TypeName PSObject -Property @{"name"=$Reporter} + $props.reporter = New-Object -TypeName PSObject -Property @{"name" = $Reporter} } if ($Parent) { - $props.parent = New-Object -TypeName PSObject -Property @{"key"=$Parent} + $props.parent = New-Object -TypeName PSObject -Property @{"key" = $Parent} } if ($Labels) { @@ -124,20 +130,19 @@ function New-JiraIssue } Write-Debug "[New-JiraIssue] Processing Fields parameter" - foreach ($k in $Fields.Keys) - { + foreach ($k in $Fields.Keys) { $name = $k $value = $Fields.$k Write-Debug "[New-JiraIssue] Attempting to identify field (name=[$name], value=[$value])" $f = Get-JiraField -Field $name -Credential $Credential - if ($f) - { + if ($f) { $id = $f.ID Write-Debug "[New-JiraIssue] Field [$name] was identified as ID [$id]" $props.$id = $value - } else { + } + else { Write-Debug "[New-JiraIssue] Field [$name] could not be identified in Jira" throw "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." } @@ -145,23 +150,22 @@ function New-JiraIssue Write-Verbose "Checking Jira createmeta to make sure all required fields are provided" Write-Debug "[New-JiraIssue] Testing Jira createmeta" - foreach ($c in $createmeta) - { - if ($c.Required) - { - if ($props.ContainsKey($c.Id)) - { + foreach ($c in $createmeta) { + if ($c.Required) { + if ($props.ContainsKey($c.Id)) { Write-Debug "[New-JiraIssue] Required field (id=[$($c.Id)], name=[$($c.Name)]) was provided (value=[$($props.$($c.Id))])" - } else { + } + else { Write-Debug "[New-JiraIssue] Required field (id=[$($c.Id)], name=[$($c.Name)]) was NOT provided. Writing error." - if ($c.Id -eq 'Reporter') - { + if ($c.Id -eq 'Reporter') { throw "Jira's metadata for project [$Project] and issue type [$IssueType] requires a reporter. Provide a value for the -Reporter parameter when creating an issue." - } else { + } + else { throw "Jira's metadata for project [$Project] and issue type [$IssueType] specifies that a field is required that was not provided (name=[$($c.Name)], id=[$($c.Id)]). You must supply this field via the -Fields parameter. Use Get-JiraIssueCreateMetadata for more information." } } - } else { + } + else { Write-Debug "[New-JiraIssue] Non-required field (id=[$($c.Id)], name=[$($c.Name)])" } } @@ -177,8 +181,7 @@ function New-JiraIssue Write-Debug "[New-JiraIssue] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $issueURL -Body $json -Credential $Credential - if ($result) - { + if ($result) { # REST result will look something like this: # {"id":"12345","key":"IT-3676","self":"http://jiraserver.example.com/rest/api/latest/issue/12345"} @@ -187,13 +190,13 @@ function New-JiraIssue $getResult = Get-JiraIssue -Key $result.Key -Credential $Credential Write-Debug "[New-JiraIssue] Writing output from New-JiraIssue" Write-Output $getResult - } else { + } + else { Write-Debug "[New-JiraIssue] Jira returned no results to output." } } - end - { + end { Write-Debug "[New-JiraIssue] Completing New-JiraIssue" } } diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index fa7dbd4a..f8cf2fac 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -24,7 +24,7 @@ function New-JiraSession #> [CmdletBinding()] param( - # Credentials to use for the persistent session + # Credentials to use to connect to JIRA. [Parameter(Mandatory = $true, Position = 0)] [System.Management.Automation.PSCredential] $Credential diff --git a/PSJira/Public/New-JiraUser.ps1 b/PSJira/Public/New-JiraUser.ps1 index 17b7605c..e8db78b2 100644 --- a/PSJira/Public/New-JiraUser.ps1 +++ b/PSJira/Public/New-JiraUser.ps1 @@ -1,5 +1,4 @@ -function New-JiraUser -{ +function New-JiraUser { <# .Synopsis Creates a new user in JIRA @@ -24,28 +23,31 @@ function New-JiraUser #> [CmdletBinding()] param( + # Name of user. [Parameter(Mandatory = $true)] [String] $UserName, + # E-mail address of the user. [Parameter(Mandatory = $true)] [Alias('Email')] [String] $EmailAddress, + # Display name of the user. [Parameter(Mandatory = $false)] [String] $DisplayName, # Should the user receive a notification e-mail? [Boolean] $Notify = $true, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential ) - begin - { + begin { Write-Debug "[New-JiraUser] Reading information from config file" - try - { + try { Write-Debug "[New-JiraUser] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { @@ -57,24 +59,23 @@ function New-JiraUser $userURL = "$server/rest/api/latest/user" } - process - { + process { Write-Debug "[New-JiraUser] Defining properties" $props = @{ - "name" = $UserName; + "name" = $UserName; "emailAddress" = $EmailAddress; } - if ($DisplayName) - { + if ($DisplayName) { $props.displayName = $DisplayName - } else { + } + else { Write-Debug "[New-JiraUser] DisplayName was not specified; defaulting to UserName parameter [$UserName]" $props.displayName = $UserName } Write-Debug "[New-JiraUser] Setting Notify property to $Notify" - $props.notify = $Notify + $props.notify = $Notify Write-Debug "[New-JiraUser] Converting to JSON" $json = ConvertTo-Json -InputObject $props @@ -82,23 +83,22 @@ function New-JiraUser Write-Debug "[New-JiraUser] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $userURL -Body $json -Credential $Credential - if ($result) - { - if ($result.errors) - { + if ($result) { + if ($result.errors) { Write-Debug "[New-JiraUser] Jira return an error result object." $keys = (Get-Member -InputObject $result.errors | Where-Object -FilterScript {$_.MemberType -eq 'NoteProperty'}).Name - foreach ($k in $keys) - { + foreach ($k in $keys) { Write-Error "Jira encountered an error: [$($k)] - $($result.errors.$k)" } - } else { + } + else { # OK Write-Debug "[New-JiraUser] Converting output object into a Jira user and outputting" ConvertTo-JiraUser -InputObject $result } - } else { + } + else { Write-Debug "[New-JiraUser] Jira returned no results to output." } } diff --git a/PSJira/Public/Remove-JiraGroup.ps1 b/PSJira/Public/Remove-JiraGroup.ps1 index 5f14ed3b..c8d71a24 100644 --- a/PSJira/Public/Remove-JiraGroup.ps1 +++ b/PSJira/Public/Remove-JiraGroup.ps1 @@ -1,5 +1,4 @@ -function Remove-JiraGroup -{ +function Remove-JiraGroup { <# .Synopsis Removes an existing group from JIRA @@ -16,25 +15,27 @@ This function returns no output. #> [CmdletBinding(SupportsShouldProcess = $true, - ConfirmImpact = 'High')] + ConfirmImpact = 'High')] param( + # Group Object or ID to delete. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true)] + Position = 0, + ValueFromPipeline = $true)] [Alias('GroupName')] [Object[]] $Group, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential, + # Suppress user confirmation. [Switch] $Force ) - begin - { + begin { Write-Debug "[Remove-JiraGroup] Reading information from config file" - try - { + try { Write-Debug "[Remove-JiraGroup] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { @@ -45,42 +46,36 @@ $restUrl = "$server/rest/api/latest/group?groupname={0}" - if ($Force) - { + if ($Force) { Write-Debug "[Remove-JiraGroup] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" $oldConfirmPreference = $ConfirmPreference $ConfirmPreference = 'None' } } - process - { - foreach ($g in $Group) - { + process { + foreach ($g in $Group) { Write-Debug "[Remove-JiraGroup] Obtaining reference to group [$g]" $groupObj = Get-JiraGroup -InputObject $g -Credential $Credential - if ($groupObj) - { + if ($groupObj) { $thisUrl = $restUrl -f $groupObj.Name Write-Debug "[Remove-JiraGroup] Group URL: [$thisUrl]" Write-Debug "[Remove-JiraGroup] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess($groupObj.Name, "Remove group [$groupObj] from JIRA")) - { + if ($PSCmdlet.ShouldProcess($groupObj.Name, "Remove group [$groupObj] from JIRA")) { Write-Debug "[Remove-JiraGroup] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential - } else { + } + else { Write-Debug "[Remove-JiraGroup] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } } } } - end - { - if ($Force) - { + end { + if ($Force) { Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" $ConfirmPreference = $oldConfirmPreference } diff --git a/PSJira/Public/Remove-JiraGroupMember.ps1 b/PSJira/Public/Remove-JiraGroupMember.ps1 index 00637509..f3c07ee0 100644 --- a/PSJira/Public/Remove-JiraGroupMember.ps1 +++ b/PSJira/Public/Remove-JiraGroupMember.ps1 @@ -1,5 +1,4 @@ -function Remove-JiraGroupMember -{ +function Remove-JiraGroupMember { <# .Synopsis Removes a user from a JIRA group @@ -24,11 +23,12 @@ function Remove-JiraGroupMember versions of JIRA. The function will need to be re-written at that time. #> [CmdletBinding(SupportsShouldProcess = $true, - ConfirmImpact = 'High')] + ConfirmImpact = 'High')] param( + # Group Object or ID from which to remove the user(s). [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true)] + Position = 0, + ValueFromPipeline = $true)] [Alias('GroupName')] [Object[]] $Group, @@ -37,17 +37,19 @@ function Remove-JiraGroupMember [Alias('UserName')] [Object[]] $User, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential, # Whether output should be provided after invoking this function [Switch] $PassThru, + # Suppress user confirmation. [Switch] $Force ) - begin - { + begin { Write-Debug "[Remove-JiraGroupMember] Reading information from config file" try { @@ -61,76 +63,69 @@ function Remove-JiraGroupMember $restUrl = "$server/rest/api/latest/group/user?groupname={0}&username={1}" - if ($Force) - { + if ($Force) { Write-Debug "[Remove-JiraGroupMember] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" $oldConfirmPreference = $ConfirmPreference $ConfirmPreference = 'None' } } - process - { - foreach ($g in $Group) - { + process { + foreach ($g in $Group) { Write-Debug "[Remove-JiraGroupMember] Obtaining reference to group [$g]" $groupObj = Get-JiraGroup -InputObject $g -Credential $Credential - if ($groupObj) - { + if ($groupObj) { Write-Debug "[Remove-JiraGroupMember] Obtaining members of group [$g]" $groupMembers = Get-JiraGroupMember -Group $g -Credential $Credential | Select-Object -ExpandProperty Name - foreach ($u in $User) - { + foreach ($u in $User) { Write-Debug "[Remove-JiraGroupMember] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) - { + if ($userObj) { Write-Debug "[Remove-JiraGroupMember] Retrieved user reference [$userObj]" - if ($groupMembers -contains $userObj.Name) - { + if ($groupMembers -contains $userObj.Name) { $thisRestUrl = $restUrl -f $groupObj.Name, $userObj.Name Write-Debug "[Remove-JiraGroupMember] REST URI: [$thisRestUrl]" Write-Debug "[Remove-JiraGroupMember] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess("$groupObj", "Remove $userObj from group")) - { + if ($PSCmdlet.ShouldProcess("$groupObj", "Remove $userObj from group")) { Write-Debug "[Remove-JiraGroupMember] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisRestUrl -Credential $Credential - } else { + } + else { Write-Debug "[Remove-JiraGroupMember] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } - } else { + } + else { Write-Debug "[Remove-JiraGroupMember] User [$u] is not currently a member of group [$g]" Write-Verbose "User [$u] is not currently a member of group [$g]" } - } else { + } + else { Write-Debug "[Remove-JiraGroupMember] Could not identify user [$u]. Writing error message." Write-Error "Unable to identify user [$u]. Check the spelling of this user and ensure that you can access it via Get-JiraUser." } } - if ($PassThru) - { + if ($PassThru) { Write-Debug "[Remove-JiraGroupMember] -PassThru specified. Obtaining a final reference to group [$g]" $groupObjNew = Get-JiraGroup -InputObject $g -Credential $Credential Write-Debug "[Remove-JiraGroupMember] Outputting group [$groupObjNew]" Write-Output $groupObjNew } - } else { + } + else { Write-Debug "[Remove-JiraGroupMember] Could not identify group [$g]" Write-Error "Unable to identify group [$g]. Check the spelling of this group and ensure that you can access it via Get-JiraGroup." } } } - end - { - if ($Force) - { + end { + if ($Force) { Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" $ConfirmPreference = $oldConfirmPreference } diff --git a/PSJira/Public/Remove-JiraRemoteLink.ps1 b/PSJira/Public/Remove-JiraRemoteLink.ps1 index b77f8e06..d7f689dd 100644 --- a/PSJira/Public/Remove-JiraRemoteLink.ps1 +++ b/PSJira/Public/Remove-JiraRemoteLink.ps1 @@ -18,7 +18,7 @@ function Remove-JiraRemoteLink [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] param( - # Issue from which to delete a remote link + # Issue from which to delete a remote link. [Parameter(ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true, @@ -27,15 +27,17 @@ function Remove-JiraRemoteLink [Alias("Key")] [Object[]] $Issue, - # Id of the remote link to delete + # Id of the remote link to delete. [Parameter(Mandatory = $true)] [Int[]] $LinkId, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential, - [Switch] $force + # Suppress user confirmation. + [Switch] $Force ) Begin diff --git a/PSJira/Public/Remove-JiraUser.ps1 b/PSJira/Public/Remove-JiraUser.ps1 index df17e47c..24c968a5 100644 --- a/PSJira/Public/Remove-JiraUser.ps1 +++ b/PSJira/Public/Remove-JiraUser.ps1 @@ -1,5 +1,4 @@ -function Remove-JiraUser -{ +function Remove-JiraUser { <# .Synopsis Removes an existing user from JIRA @@ -19,25 +18,27 @@ function Remove-JiraUser This function returns no output. #> [CmdletBinding(SupportsShouldProcess = $true, - ConfirmImpact = 'High')] + ConfirmImpact = 'High')] param( + # User Object or ID to delete. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true)] + Position = 0, + ValueFromPipeline = $true)] [Alias('UserName')] [Object[]] $User, + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [PSCredential] $Credential, + # Suppress user confirmation. [Switch] $Force ) - begin - { + begin { Write-Debug "[Remove-JiraUser] Reading information from config file" - try - { + try { Write-Debug "[Remove-JiraUser] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { @@ -48,42 +49,36 @@ function Remove-JiraUser $userURL = "$server/rest/api/latest/user?username={0}" - if ($Force) - { + if ($Force) { Write-Debug "[Remove-JiraGroup] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" $oldConfirmPreference = $ConfirmPreference $ConfirmPreference = 'None' } } - process - { - foreach ($u in $User) - { + process { + foreach ($u in $User) { Write-Debug "[Remove-JiraUser] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) - { + if ($userObj) { $thisUrl = $userUrl -f $userObj.Name Write-Debug "[Remove-JiraUser] User URL: [$thisUrl]" Write-Debug "[Remove-JiraUser] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess($userObj.Name, 'Completely remove user from JIRA')) - { + if ($PSCmdlet.ShouldProcess($userObj.Name, 'Completely remove user from JIRA')) { Write-Debug "[Remove-JiraUser] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential - } else { + } + else { Write-Debug "[Remove-JiraUser] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } } } } - end - { - if ($Force) - { + end { + if ($Force) { Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" $ConfirmPreference = $oldConfirmPreference } diff --git a/PSJira/Public/Set-JiraConfigServer.ps1 b/PSJira/Public/Set-JiraConfigServer.ps1 index a669e6e3..5de6cc84 100644 --- a/PSJira/Public/Set-JiraConfigServer.ps1 +++ b/PSJira/Public/Set-JiraConfigServer.ps1 @@ -27,6 +27,7 @@ function Set-JiraConfigServer [Alias('Uri')] [String] $Server, + # Path where the file with the configuration will be stored. [String] $ConfigFile ) diff --git a/PSJira/Public/Set-JiraIssue.ps1 b/PSJira/Public/Set-JiraIssue.ps1 index d6d24857..f0039922 100644 --- a/PSJira/Public/Set-JiraIssue.ps1 +++ b/PSJira/Public/Set-JiraIssue.ps1 @@ -25,7 +25,7 @@ function Set-JiraIssue #> [CmdletBinding(DefaultParameterSetName = 'ByInputObject')] param( - # Issue key or PSJira.Issue object returned from Get-JiraIssue + # Issue key or PSJira.Issue object returned from Get-JiraIssue. [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, @@ -33,11 +33,11 @@ function Set-JiraIssue [Alias('Key')] [Object[]] $Issue, - # New summary of the issue + # New summary of the issue. [Parameter(Mandatory = $false)] [String] $Summary, - # New description of the issue + # New description of the issue. [Parameter(Mandatory = $false)] [String] $Description, @@ -50,16 +50,19 @@ function Set-JiraIssue # use Set-JiraIssueLabel. [String[]] $Label, - # Any additional fields that should be updated + # Any additional fields that should be updated. [System.Collections.Hashtable] $Fields, + # Path of the file where the configuration is stored. [ValidateScript({Test-Path $_})] [String] $ConfigFile, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential, + # Whether output should be provided after invoking this function. [Switch] $PassThru ) diff --git a/PSJira/Public/Set-JiraIssueLabel.ps1 b/PSJira/Public/Set-JiraIssueLabel.ps1 index 1e6b2ae3..b44f51c6 100644 --- a/PSJira/Public/Set-JiraIssueLabel.ps1 +++ b/PSJira/Public/Set-JiraIssueLabel.ps1 @@ -1,5 +1,4 @@ -function Set-JiraIssueLabel -{ +function Set-JiraIssueLabel { <# .Synopsis Modifies labels on an existing JIRA issue @@ -30,53 +29,53 @@ #> [CmdletBinding(DefaultParameterSetName = 'ReplaceLabels')] param( - # Issue key or PSJira.Issue object returned from Get-JiraIssue + # Issue key or PSJira.Issue object returned from Get-JiraIssue. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Alias('Key')] [Object[]] $Issue, + # List of labels that will be set to the issue. + # Any label that was already assigned to the issue will be removed. [Parameter(ParameterSetName = 'ReplaceLabels', - Mandatory = $true)] - [Alias('Label','Replace')] + Mandatory = $true)] + [Alias('Label', 'Replace')] [String[]] $Set, - # Existing labels to be added + # Existing labels to be added. [Parameter(ParameterSetName = 'ModifyLabels')] [String[]] $Add, - # Existing labels to be removed + # Existing labels to be removed. [Parameter(ParameterSetName = 'ModifyLabels')] [String[]] $Remove, - # Remove all labels + # Remove all labels. [Parameter(ParameterSetName = 'ClearLabels')] [Switch] $Clear, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential, + # Whether output should be provided after invoking this function. [Switch] $PassThru ) - begin - { + begin { Write-Debug "[Set-JiraIssueLabel] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } - process - { - foreach ($i in $Issue) - { + process { + foreach ($i in $Issue) { Write-Debug "[Set-JiraIssueLabel] Obtaining reference to issue" $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential - if ($issueObj) - { + if ($issueObj) { $currentLabels = @($issueObj.labels) $url = $issueObj.RestURL $isDirty = $true @@ -89,24 +88,26 @@ # issue object and use the Set verb for everything, so we only # have to make one call to JIRA. - if ($Clear) - { + if ($Clear) { Write-Debug "[Set-JiraIssueLabel] Clearing all labels" $newLabels = @() - } elseif ($PSCmdlet.ParameterSetName -eq 'ReplaceLabels') { + } + elseif ($PSCmdlet.ParameterSetName -eq 'ReplaceLabels') { Write-Debug "[Set-JiraIssueLabel] Set parameter was used; existing labels will be overwritten" $newLabels = $Set - } elseif ($currentLabels -eq $null -or $currentLabels.Count -eq 0) { + } + elseif ($currentLabels -eq $null -or $currentLabels.Count -eq 0) { Write-Debug "[Set-JiraIssueLabel] Issue currently has no labels" - if ($Add) - { + if ($Add) { Write-Debug "[Set-JiraIssueLabel] Setting labels to Add parameter" $newLabels = $Add - } else { + } + else { Write-Debug "[Set-JiraIssueLabel] No labels were specified to be added; nothing to do" $isDirty = $false } - } else { + } + else { Write-Debug "[Set-JiraIssueLabel] Calculating new labels" # If $Add is not provided (null), this can end up with an # extra $null being added to the array, so we need to @@ -115,8 +116,7 @@ $newLabels = $currentLabels + $Add | Where-Object -FilterScript {$_ -ne $null -and $Remove -notcontains $_} } - if ($isDirty) - { + if ($isDirty) { Write-Debug "[Set-JiraIssueLabel] New labels for the issue: [$($newLabels -join ',')]" $props = @{ @@ -136,24 +136,24 @@ Write-Debug "[Set-JiraIssueLabel] Preparing for blastoff!" # Should return no results $result = Invoke-JiraMethod -Method Put -URI $url -Body $json -Credential $Credential - } else { + } + else { Write-Debug "[Set-JiraIssueLabel] No changes are necessary." } - if ($PassThru) - { + if ($PassThru) { Write-Debug "[Set-JiraIssue] PassThru was specified. Obtaining updated reference to issue" Get-JiraIssue -Key $issueObj.Key -Credential $Credential } - } else { + } + else { Write-Debug "[Set-JiraIssue] Unable to identify issue [$i]. Writing error message." Write-Error "Unable to identify issue [$i]" } } } - end - { + end { Write-Debug "[Set-JiraIssueLabel] Complete" } } diff --git a/PSJira/Public/Set-JiraUser.ps1 b/PSJira/Public/Set-JiraUser.ps1 index b4adbc44..11c3cc8e 100644 --- a/PSJira/Public/Set-JiraUser.ps1 +++ b/PSJira/Public/Set-JiraUser.ps1 @@ -27,7 +27,7 @@ function Set-JiraUser #> [CmdletBinding(DefaultParameterSetName = 'ByNamedParameters')] param( - # Username or user object obtained from Get-JiraUser + # Username or user object obtained from Get-JiraUser. [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, @@ -35,23 +35,28 @@ function Set-JiraUser [Alias('UserName')] [Object[]] $User, + # Display name to set. [Parameter(ParameterSetName = 'ByNamedParameters', Mandatory = $false)] [String] $DisplayName, + # E-mail address to set. [Parameter(ParameterSetName = 'ByNamedParameters', Mandatory = $false)] [String] $EmailAddress, + # Hashtable (dictionary) of additional information to set. [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $true, Position = 1)] [Hashtable] $Property, - # Credentials to use to connect to Jira + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential, + # Whether output should be provided after invoking this function. [Switch] $PassThru ) From b1270b78814d0ebc6b04c3b56168dc451ef4829c Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 22 May 2017 17:21:18 +0200 Subject: [PATCH 041/102] [fix] updated the code formatting I screwed up in my last commit --- PSJira/Public/Add-JiraGroupMember.ps1 | 52 ++++++----- PSJira/Public/Add-JiraIssueComment.ps1 | 62 +++++++------ PSJira/Public/Format-Jira.ps1 | 28 +++--- PSJira/Public/Get-JiraComponent.ps1 | 26 ++++-- PSJira/Public/Get-JiraConfigServer.ps1 | 20 +++-- PSJira/Public/Get-JiraField.ps1 | 19 ++-- PSJira/Public/Get-JiraFilter.ps1 | 42 ++++++--- PSJira/Public/Get-JiraGroup.ps1 | 26 +++--- PSJira/Public/Get-JiraGroupMember.ps1 | 51 +++++++---- PSJira/Public/Get-JiraIssue.ps1 | 87 ++++++++++++------- PSJira/Public/Get-JiraIssueComment.ps1 | 13 +-- PSJira/Public/Get-JiraIssueCreateMetadata.ps1 | 31 ++++--- PSJira/Public/Get-JiraIssueEditMetadata.ps1 | 19 ++-- PSJira/Public/Get-JiraIssueType.ps1 | 19 ++-- PSJira/Public/Get-JiraPriority.ps1 | 6 +- PSJira/Public/Get-JiraProject.ps1 | 17 ++-- PSJira/Public/Get-JiraRemoteLink.ps1 | 25 ++++-- PSJira/Public/Get-JiraSession.ps1 | 10 ++- PSJira/Public/Get-JiraUser.ps1 | 28 +++--- PSJira/Public/Invoke-JiraIssueTransition.ps1 | 41 +++++---- PSJira/Public/New-JiraGroup.ps1 | 21 +++-- PSJira/Public/New-JiraIssue.ps1 | 75 ++++++++++------ PSJira/Public/New-JiraSession.ps1 | 14 +-- PSJira/Public/New-JiraUser.ps1 | 38 +++++--- PSJira/Public/Remove-JiraGroup.ps1 | 36 +++++--- PSJira/Public/Remove-JiraGroupMember.ps1 | 58 ++++++++----- PSJira/Public/Remove-JiraRemoteLink.ps1 | 20 +++-- PSJira/Public/Remove-JiraSession.ps1 | 28 +++--- PSJira/Public/Remove-JiraUser.ps1 | 38 +++++--- PSJira/Public/Set-JiraConfigServer.ps1 | 44 +++++----- PSJira/Public/Set-JiraIssue.ps1 | 26 +++--- PSJira/Public/Set-JiraIssueLabel.ps1 | 48 ++++++---- PSJira/Public/Set-JiraUser.ps1 | 32 ++++--- Tests/PSJira.Help.Tests.ps1 | 56 ++++++------ 34 files changed, 720 insertions(+), 436 deletions(-) diff --git a/PSJira/Public/Add-JiraGroupMember.ps1 b/PSJira/Public/Add-JiraGroupMember.ps1 index 285397f9..cd6630cd 100644 --- a/PSJira/Public/Add-JiraGroupMember.ps1 +++ b/PSJira/Public/Add-JiraGroupMember.ps1 @@ -1,4 +1,5 @@ -function Add-JiraGroupMember { +function Add-JiraGroupMember +{ <# .Synopsis Adds a user to a JIRA group @@ -45,12 +46,15 @@ function Add-JiraGroupMember { [Switch] $PassThru ) - begin { + begin + { Write-Debug "[Add-JiraGroupMember] Reading information from config file" - try { + try + { Write-Debug "[Add-JiraGroupMember] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Add-JiraGroupMember] Encountered an error reading configuration data." throw $err @@ -65,11 +69,13 @@ function Add-JiraGroupMember { # request, which we'll loop through again in the Process block. $userAL = New-Object -TypeName System.Collections.ArrayList - foreach ($u in $User) { + foreach ($u in $User) + { Write-Debug "[Add-JiraGroupMember] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) { + if ($userObj) + { Write-Debug "[Add-JiraGroupMember] Retrieved user reference [$userObj]" # $thisUserJson = ConvertTo-Json -InputObject @{ # 'name' = $userObj.Name; @@ -77,7 +83,8 @@ function Add-JiraGroupMember { # [void] $userAL.Add($thisUserJson) [void] $userAL.Add($userObj.Name) } - else { + else + { Write-Debug "[Add-JiraGroupMember] Could not identify user [$u]. Writing error message." Write-Error "Unable to identify user [$u]. Check the spelling of this user and ensure that you can access it via Get-JiraUser." } @@ -89,12 +96,15 @@ function Add-JiraGroupMember { $restUrl = "$server/rest/api/latest/group/user?groupname={0}" } - process { - foreach ($g in $Group) { + process + { + foreach ($g in $Group) + { Write-Debug "[Add-JiraGroupMember] Obtaining reference to group [$g]" $groupObj = Get-JiraGroup -InputObject $g -Credential $Credential - if ($groupObj) { + if ($groupObj) + { Write-Debug "[Add-JiraGroupMember] Obtaining members of group [$g]" $groupMembers = Get-JiraGroupMember -Group $g -Credential $Credential | Select-Object -ExpandProperty Name @@ -105,8 +115,10 @@ function Add-JiraGroupMember { # Write-Debug "[Add-JiraGroupMember] Preparing for blastoff!" # $result = Invoke-JiraMethod -Method Post -URI $thisRestUrl -Body $json -Credential $Credential # } - foreach ($u in $userNames) { - if ($groupMembers -notcontains $u) { + foreach ($u in $userNames) + { + if ($groupMembers -notcontains $u) + { Write-Debug "[Add-JiraGroupMember] User [$u] is not already in group [$g]. Adding user." $userJson = ConvertTo-Json -InputObject @{ 'name' = $u; @@ -114,31 +126,31 @@ function Add-JiraGroupMember { Write-Debug "[Add-JiraGroupMember] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $thisRestUrl -Body $userJson -Credential $Credential } - else { + else + { Write-Debug "[Add-JiraGroupMember] User [$u] is already a member of group [$g]" Write-Verbose "User [$u] is already a member of group [$g]" } } - if ($PassThru) { + if ($PassThru) + { Write-Debug "[Add-JiraGroupMember] -PassThru specified. Obtaining a final reference to group [$g]" $groupObjNew = Get-JiraGroup -InputObject $g -Credential $Credential Write-Debug "[Add-JiraGroupMember] Outputting group [$groupObjNew]" Write-Output $groupObjNew } } - else { + else + { Write-Debug "[Add-JiraGroupMember] Could not identify group [$g]" Write-Error "Unable to identify group [$g]. Check the spelling of this group and ensure that you can access it via Get-JiraGroup." } } } - end { + end + { Write-Debug "[Add-JiraGroupMember] Complete" } } - - - - diff --git a/PSJira/Public/Add-JiraIssueComment.ps1 b/PSJira/Public/Add-JiraIssueComment.ps1 index 3c6659e9..055ff3fe 100644 --- a/PSJira/Public/Add-JiraIssueComment.ps1 +++ b/PSJira/Public/Add-JiraIssueComment.ps1 @@ -29,19 +29,19 @@ function Add-JiraIssueComment param( # Comment that should be added to JIRA. [Parameter(Mandatory = $true, - Position = 0)] + Position = 0)] [String] $Comment, # Issue that should be commented upon. [Parameter(Mandatory = $true, - Position = 1, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 1, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Alias('Key')] [Object] $Issue, # Visibility of the comment - should it be publicly visible, viewable to only developers, or only administrators? - [ValidateSet('All Users','Developers','Administrators')] + [ValidateSet('All Users', 'Developers', 'Administrators')] [String] $VisibleRole = 'Developers', # Credentials to use to connect to JIRA. @@ -58,30 +58,30 @@ function Add-JiraIssueComment process { -# Write-Debug "[Add-JiraIssueComment] Checking Issue parameter" -# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') -# { -# Write-Debug "[Add-JiraIssueComment] Issue parameter is a PSJira.Issue object" -# $issueObj = $Issue -# } else { -# $issueKey = $Issue.ToString() -# Write-Debug "[Add-JiraIssueComment] Issue key is assumed to be [$issueKey] via ToString()" -# Write-Verbose "Searching for issue [$issueKey]" -# try -# { -# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential -# } catch { -# $err = $_ -# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' -# throw $err -# } -# } -# -# if (-not $issueObj) -# { -# Write-Debug "[Add-JiraIssueComment] No Jira issues were found for parameter [$Issue]. An exception will be thrown." -# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" -# } + # Write-Debug "[Add-JiraIssueComment] Checking Issue parameter" + # if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') + # { + # Write-Debug "[Add-JiraIssueComment] Issue parameter is a PSJira.Issue object" + # $issueObj = $Issue + # } else { + # $issueKey = $Issue.ToString() + # Write-Debug "[Add-JiraIssueComment] Issue key is assumed to be [$issueKey] via ToString()" + # Write-Verbose "Searching for issue [$issueKey]" + # try + # { + # $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential + # } catch { + # $err = $_ + # Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' + # throw $err + # } + # } + # + # if (-not $issueObj) + # { + # Write-Debug "[Add-JiraIssueComment] No Jira issues were found for parameter [$Issue]. An exception will be thrown." + # throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" + # } Write-Debug "[Add-JiraIssueComment] Obtaining a reference to Jira issue [$Issue]" $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential @@ -99,7 +99,7 @@ function Add-JiraIssueComment if ($VisibleRole -ne 'All Users') { $props.visibility = @{ - 'type' = 'role'; + 'type' = 'role'; 'value' = $VisibleRole; } } @@ -122,5 +122,3 @@ function Add-JiraIssueComment Write-Debug "[Add-JiraIssueComment] Complete" } } - - diff --git a/PSJira/Public/Format-Jira.ps1 b/PSJira/Public/Format-Jira.ps1 index 10c0cca0..9ca8dbe0 100644 --- a/PSJira/Public/Format-Jira.ps1 +++ b/PSJira/Public/Format-Jira.ps1 @@ -27,13 +27,13 @@ function Format-Jira # # To display all properties, use -Property *. [Parameter(Mandatory = $false, - Position = 0)] + Position = 0)] [Object[]] $Property, # Object to format. [Parameter(Mandatory = $true, - ValueFromPipeline = $true, - ValueFromRemainingArguments = $true)] + ValueFromPipeline = $true, + ValueFromRemainingArguments = $true)] [ValidateNotNull()] [PSObject[]] $InputObject ) @@ -53,7 +53,9 @@ function Format-Jira if ($Property -eq '*') { Write-Debug "[Format-Jira] -Property * was passed. Adding all properties." - } else { + } + else + { foreach ($p in $Property) { @@ -66,7 +68,9 @@ function Format-Jira [void] $allText.Append($headerString) $headerDefined = $true } - } else { + } + else + { Write-Debug "[Format-Jira] Property parameter was not specified. Checking first InputObject for property names." } } @@ -87,7 +91,9 @@ function Format-Jira Write-Debug "[Format-Jira] Adding header [$($a.Name)]" [void] $headers.Add($a.Name) } - } else { + } + else + { # TODO: find a way to format output objects based on PowerShell's own Format-Table # Identify default table properties if possible and use them to create a Jira table @@ -102,7 +108,9 @@ function Format-Jira Write-Debug "[Format-Jira] Adding header [$p]" [void] $headers.Add($p) } - } else { + } + else + { Write-Debug "[Format-Jira] No default format data exists for object [$i] (type=[$($i.GetType())]). All properties will be used." $allProperties = Get-Member -InputObject $i -MemberType '*Property' foreach ($a in $allProperties) @@ -130,7 +138,9 @@ function Format-Jira { Write-Debug "[Format-Jira] Adding property (name=[$h], value=[$value])" [void] $thisLine.Append("$value|") - } else { + } + else + { Write-Debug "[Format-Jira] Property [$h] does not exist on this object." [void] $thisLine.Append(' |') } @@ -149,5 +159,3 @@ function Format-Jira Write-Debug "[Format-Jira] Complete" } } - - diff --git a/PSJira/Public/Get-JiraComponent.ps1 b/PSJira/Public/Get-JiraComponent.ps1 index bee86a7c..6848fa6b 100644 --- a/PSJira/Public/Get-JiraComponent.ps1 +++ b/PSJira/Public/Get-JiraComponent.ps1 @@ -30,14 +30,14 @@ function Get-JiraComponent param( # The Project ID or project key of a project to search. [Parameter(ParameterSetName = 'ByProject', - ValueFromPipeline, - Mandatory = $true)] + ValueFromPipeline, + Mandatory = $true)] $Project, # The Component ID. [Parameter(Mandatory = $true, - Position = 0, - ParameterSetName = 'ByID')] + Position = 0, + ParameterSetName = 'ByID')] [Alias("Id")] [int[]] $ComponentId, @@ -53,7 +53,8 @@ function Get-JiraComponent try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraComponent] Encountered an error reading the Jira server." throw $err @@ -66,9 +67,12 @@ function Get-JiraComponent { if ($Project) { - if ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project') { + if ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project') + { $ComponentId = @($Project.Components | Select-Object -ExpandProperty id) - } else { + } + else + { foreach ($p in $Project) { if ($p -is [string]) @@ -86,7 +90,9 @@ function Get-JiraComponent Write-Debug "[Get-JiraComponent] Outputting result" Write-Output $obj - } else { + } + else + { Write-Debug "[Get-JiraComponent] No results were returned from Jira" Write-Debug "[Get-JiraComponent] No results were returned from Jira for component [$i]" } @@ -111,7 +117,9 @@ function Get-JiraComponent Write-Debug "[Get-JiraComponent] Outputting result" Write-Output $obj - } else { + } + else + { Write-Debug "[Get-JiraComponent] No results were returned from Jira" Write-Debug "[Get-JiraComponent] No results were returned from Jira for component [$i]" } diff --git a/PSJira/Public/Get-JiraConfigServer.ps1 b/PSJira/Public/Get-JiraConfigServer.ps1 index 1818de67..5559c6ef 100644 --- a/PSJira/Public/Get-JiraConfigServer.ps1 +++ b/PSJira/Public/Get-JiraConfigServer.ps1 @@ -32,12 +32,12 @@ function Get-JiraConfigServer if (-not ($ConfigFile)) { -# Write-Debug "[Get-JiraConfigServer] ConfigFile was not provided, or provided with a null value" + # Write-Debug "[Get-JiraConfigServer] ConfigFile was not provided, or provided with a null value" # This file should be in $moduleRoot/Functions/Internal, so PSScriptRoot will be $moduleRoot/Functions $moduleFolder = Split-Path -Path $PSScriptRoot -Parent -# Write-Debug "[Get-JiraConfigServer] Module folder: $moduleFolder" + # Write-Debug "[Get-JiraConfigServer] Module folder: $moduleFolder" $ConfigFile = Join-Path -Path $moduleFolder -ChildPath 'config.xml' -# Write-Debug "[Get-JiraConfigServer] Using default config file at [$ConfigFile]" + # Write-Debug "[Get-JiraConfigServer] Using default config file at [$ConfigFile]" } if (-not (Test-Path -Path $ConfigFile)) @@ -45,7 +45,7 @@ function Get-JiraConfigServer throw "Config file [$ConfigFile] does not exist. Use Set-JiraConfigServer first to define the configuration file." } -# Write-Debug "Loading config file '$ConfigFile'" + # Write-Debug "Loading config file '$ConfigFile'" $xml = New-Object -TypeName XML $xml.Load($ConfigFile) @@ -55,15 +55,17 @@ function Get-JiraConfigServer throw "Unexpected document element [$($xmlConfig.LocalName)] in configuration file [$ConfigFile]. You may need to delete the config file and recreate it using Set-JiraConfigServer." } -# Write-Debug "[Get-JiraConfigServer] Checking for Server element" + # Write-Debug "[Get-JiraConfigServer] Checking for Server element" if ($xmlConfig.Server) { -# Write-Debug "[Get-JiraConfigServer] Found Server element. Outputting." + # Write-Debug "[Get-JiraConfigServer] Found Server element. Outputting." Write-Output $xmlConfig.Server - } else { -# Write-Debug "[Get-JiraConfigServer] No Server element is defined in the config file. Throwing exception." + } + else + { + # Write-Debug "[Get-JiraConfigServer] No Server element is defined in the config file. Throwing exception." throw "No Server element is defined in the config file. Use Set-JiraConfigServer to define one." } -# Write-Debug "[Get-JiraConfigServer] Complete." + # Write-Debug "[Get-JiraConfigServer] Complete." } diff --git a/PSJira/Public/Get-JiraField.ps1 b/PSJira/Public/Get-JiraField.ps1 index c23b0f0f..5267a371 100644 --- a/PSJira/Public/Get-JiraField.ps1 +++ b/PSJira/Public/Get-JiraField.ps1 @@ -24,8 +24,8 @@ param( # The Field name or ID to search. [Parameter(Mandatory = $false, - Position = 0, - ValueFromRemainingArguments = $true)] + Position = 0, + ValueFromRemainingArguments = $true)] [String[]] $Field, # Credentials to use to connect to JIRA. @@ -40,7 +40,8 @@ try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraField] Encountered an error reading the Jira server." throw $err @@ -64,20 +65,26 @@ { Write-Debug "[Get-JiraField] Found results; outputting" Write-Output $thisField - } else { + } + else + { Write-Debug "[Get-JiraField] No results were found for issue type by name. Searching for issue type (id=[$i])" $thisField = $allFields | Where-Object -FilterScript {$_.Id -eq $f} if ($thisField) { Write-Debug "[Get-JiraField] Found results; outputting" Write-Output $thisField - } else { + } + else + { Write-Debug "[Get-JiraField] No results were found for issue type by ID. This issue type appears to be unknown." Write-Verbose "Unable to identify Jira field [$f]" } } } - } else { + } + else + { Write-Debug "[Get-JiraField] No Field was supplied. Outputting all fields." Write-Output $allFields } diff --git a/PSJira/Public/Get-JiraFilter.ps1 b/PSJira/Public/Get-JiraFilter.ps1 index 573f8b0f..dd184551 100644 --- a/PSJira/Public/Get-JiraFilter.ps1 +++ b/PSJira/Public/Get-JiraFilter.ps1 @@ -1,4 +1,5 @@ -function Get-JiraFilter { +function Get-JiraFilter +{ <# .Synopsis Returns information about a filter in JIRA @@ -38,11 +39,14 @@ [System.Management.Automation.PSCredential] $Credential ) - begin { + begin + { Write-Debug "[Get-JiraFilter] Reading server from config file" - try { + try + { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraFilter] Encountered an error reading the Jira server." throw $err @@ -51,36 +55,45 @@ $uri = "$server/rest/api/latest/filter/{0}" } - process { - if ($PSCmdlet.ParameterSetName -eq 'ByFilterID') { - foreach ($i in $Id) { + process + { + if ($PSCmdlet.ParameterSetName -eq 'ByFilterID') + { + foreach ($i in $Id) + { Write-Debug "[Get-JiraFilter] Processing filter [$i]" $thisUri = $uri -f $i Write-Debug "[Get-JiraFilter] Filter URI: [$thisUri]" Write-Debug "[Get-JiraFilter] Preparing for blast off!" $result = Invoke-JiraMethod -Method Get -URI $thisUri -Credential $Credential - if ($result) { + if ($result) + { Write-Debug "[Get-JiraFilter] Converting result to JiraFilter object" $obj = ConvertTo-JiraFilter -InputObject $result Write-Debug "Outputting result" Write-Output $obj } - else { + else + { Write-Debug "[Get-JiraFilter] Invoke-JiraFilter returned no results to output." } } } - else { - foreach ($i in $InputObject) { + else + { + foreach ($i in $InputObject) + { Write-Debug "[Get-JiraFilter] Processing InputObject [$i]" - if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Filter') { + if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Filter') + { Write-Debug "[Get-JiraFilter] User parameter is a PSJira.Filter object" $thisId = $i.ID } - else { + else + { $thisId = $i.ToString() Write-Debug "[Get-JiraFilter] ID is assumed to be [$thisId] via ToString()" } @@ -93,7 +106,8 @@ } } - end { + end + { Write-Debug "[Get-JiraFilter] Complete" } } diff --git a/PSJira/Public/Get-JiraGroup.ps1 b/PSJira/Public/Get-JiraGroup.ps1 index b5b8def0..a20a8a2f 100644 --- a/PSJira/Public/Get-JiraGroup.ps1 +++ b/PSJira/Public/Get-JiraGroup.ps1 @@ -24,18 +24,18 @@ function Get-JiraGroup param( # Name of the group to search for. [Parameter(ParameterSetName = 'ByGroupName', - Mandatory = $true, - Position = 0)] + Mandatory = $true, + Position = 0)] [ValidateNotNullOrEmpty()] [Alias('Name')] [String[]] $GroupName, # Object of the group to search for. [Parameter(ParameterSetName = 'ByInputObject', - Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Mandatory = $true, + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Object[]] $InputObject, # Credentials to use to connect to JIRA. @@ -77,12 +77,16 @@ function Get-JiraGroup Write-Debug "[Get-JiraGroup] Outputting results" Write-Output $obj - } else { + } + else + { Write-Debug "[Get-JiraGroup] No results were returned from JIRA" Write-Verbose "No results were returned from JIRA." } } - } else { + } + else + { foreach ($i in $InputObject) { Write-Debug "[Get-JiraGroup] Processing InputObject [$i]" @@ -90,7 +94,9 @@ function Get-JiraGroup { Write-Debug "[Get-JiraGroup] User parameter is a PSJira.Group object" $thisGroupName = $i.Name - } else { + } + else + { $thisGroupName = $i.ToString() Write-Debug "[Get-JiraGroup] Username is assumed to be [$thisGroupName] via ToString()" } @@ -108,5 +114,3 @@ function Get-JiraGroup Write-Debug "[Get-JiraGroup] Complete" } } - - diff --git a/PSJira/Public/Get-JiraGroupMember.ps1 b/PSJira/Public/Get-JiraGroupMember.ps1 index 0c5bf283..c346c3d8 100644 --- a/PSJira/Public/Get-JiraGroupMember.ps1 +++ b/PSJira/Public/Get-JiraGroupMember.ps1 @@ -1,4 +1,5 @@ -function Get-JiraGroupMember { +function Get-JiraGroupMember +{ <# .Synopsis Returns members of a given group in JIRA @@ -53,30 +54,38 @@ function Get-JiraGroupMember { [System.Management.Automation.PSCredential] $Credential ) - begin { + begin + { # This is a parameter in Get-JiraIssue, but in testing, JIRA doesn't # reliably return more than 50 results at a time. $pageSize = 50 - if ($MaxResults -eq 0) { + if ($MaxResults -eq 0) + { Write-Debug "[Get-JiraGroupMember] MaxResults was not specified. Using loop mode to obtain all members." $loopMode = $true } - else { + else + { $loopMode = $false - if ($MaxResults -gt 50) { + if ($MaxResults -gt 50) + { Write-Warning "JIRA's API may not properly support MaxResults values higher than 50 for this method. If you receive inconsistent results, do not pass the MaxResults parameter to this function to return all results." } } } - process { + process + { Write-Debug "[Get-JiraGroupMember] Obtaining a reference to Jira group [$Group]" $groupObj = Get-JiraGroup -GroupName $Group -Credential $Credential - if ($groupObj) { - foreach ($g in $groupObj) { - if ($loopMode) { + if ($groupObj) + { + foreach ($g in $groupObj) + { + if ($loopMode) + { # Using the Size property of the group object, iterate # through all users in a given group. @@ -84,18 +93,22 @@ function Get-JiraGroupMember { $allUsers = New-Object -TypeName System.Collections.ArrayList Write-Debug "[Get-JiraGroupMember] Paging through all results (loop mode)" - for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) { - if ($PageSize -gt ($i + $totalResults)) { + for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) + { + if ($PageSize -gt ($i + $totalResults)) + { $thisPageSize = $totalResults - $i } - else { + else + { $thisPageSize = $PageSize } $percentComplete = ($i / $totalResults) * 100 Write-Progress -Activity 'Get-JiraGroupMember' -Status "Obtaining members ($i - $($i + $thisPageSize) of $totalResults)..." -PercentComplete $percentComplete Write-Debug "[Get-JiraGroupMember] Obtaining members $i - $($i + $thisPageSize)..." $thisSection = Get-JiraGroupMember -Group $g -StartIndex $i -MaxResults $thisPageSize -Credential $Credential - foreach ($t in $thisSection) { + foreach ($t in $thisSection) + { [void] $allUsers.Add($t) } } @@ -104,7 +117,8 @@ function Get-JiraGroupMember { Write-Output ($allUsers.ToArray()) } - else { + else + { # Since user is an expandable property of the returned # group from JIRA, JIRA doesn't use the MaxResults argument # found in other REST endpoints. Instead, we need to pass @@ -114,7 +128,8 @@ function Get-JiraGroupMember { Write-Debug "[Get-JiraGroupMember] Preparing for blastoff!" $groupResult = Invoke-JiraMethod -Method Get -URI $url -Credential $Credential - if ($groupResult) { + if ($groupResult) + { # ConvertTo-JiraGroup contains logic to convert and add # users (group members) to user objects if the members # are returned from JIRA. @@ -125,7 +140,8 @@ function Get-JiraGroupMember { Write-Debug "[Get-JiraGroupMember] Outputting group members" Write-Output $groupObjResult.Member } - else { + else + { # Something is wrong here...we didn't get back a result from JIRA when we *did* get a # valid group from Get-JiraGroup earlier. Write-Warning "A JIRA group could not be found at URL [$url], even though this seems to be a valid group." @@ -133,7 +149,8 @@ function Get-JiraGroupMember { } } } - else { + else + { throw "Unable to identify group [$Group]. Use Get-JiraGroup to make sure this is a valid JIRA group." } } diff --git a/PSJira/Public/Get-JiraIssue.ps1 b/PSJira/Public/Get-JiraIssue.ps1 index 30dd8f6d..82df0564 100644 --- a/PSJira/Public/Get-JiraIssue.ps1 +++ b/PSJira/Public/Get-JiraIssue.ps1 @@ -1,4 +1,5 @@ -function Get-JiraIssue { +function Get-JiraIssue +{ <# .Synopsis Returns information about an issue in JIRA. @@ -81,7 +82,8 @@ function Get-JiraIssue { [System.Management.Automation.PSCredential] $Credential ) - begin { + begin + { Write-Debug "[Get-JiraIssue] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop @@ -89,45 +91,56 @@ function Get-JiraIssue { $psName = $PSCmdlet.ParameterSetName - if (($psName -eq 'ByJQL' -or $psName -eq 'ByFilter') -and $MaxResults -eq 0) { + if (($psName -eq 'ByJQL' -or $psName -eq 'ByFilter') -and $MaxResults -eq 0) + { Write-Debug "[Get-JiraIssue] Using loop mode to obtain all results" $MaxResults = 1 $loopMode = $true } - else { + else + { $loopMode = $false } } - process { - if ($PSCmdlet.ParameterSetName -eq 'ByIssueKey') { - foreach ($k in $Key) { + process + { + if ($PSCmdlet.ParameterSetName -eq 'ByIssueKey') + { + foreach ($k in $Key) + { Write-Debug "[Get-JiraIssue] Processing issue key [$k]" $issueURL = "$($server)/rest/api/latest/issue/${k}?expand=transitions" Write-Debug "[Get-JiraIssue] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential - if ($result) { + if ($result) + { Write-Debug "[Get-JiraIssue] Converting REST result to Jira object" $obj = ConvertTo-JiraIssue -InputObject $result Write-Debug "[Get-JiraIssue] Outputting result" Write-Output $obj } - else { + else + { Write-Debug "[Get-JiraIssue] Invoke-JiraMethod returned no results to output." } } } - elseif ($PSCmdlet.ParameterSetName -eq 'ByInputObject') { - foreach ($i in $InputObject) { + elseif ($PSCmdlet.ParameterSetName -eq 'ByInputObject') + { + foreach ($i in $InputObject) + { Write-Debug "[Get-JiraIssue] Processing InputObject [$i]" - if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Issue') { + if ((Get-Member -InputObject $i).TypeName -eq 'PSJira.Issue') + { Write-Debug "[Get-JiraIssue] Issue parameter is a PSJira.Issue object" $issueKey = $i.Key } - else { + else + { $issueKey = $i.ToString() Write-Debug "[Get-JiraIssue] Issue key is assumed to be [$issueKey] via ToString()" } @@ -138,7 +151,8 @@ function Get-JiraIssue { Write-Output $issueObj } } - elseif ($PSCmdlet.ParameterSetName -eq 'ByJQL') { + elseif ($PSCmdlet.ParameterSetName -eq 'ByJQL') + { Write-Debug "[Get-JiraIssue] Escaping query and building URL" $escapedQuery = [System.Web.HttpUtility]::UrlPathEncode($Query) @@ -147,46 +161,55 @@ function Get-JiraIssue { Write-Debug "[Get-JiraIssue] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Get -URI $issueURL -Credential $Credential - if ($result) { + if ($result) + { # {"startAt":0,"maxResults":50,"total":0,"issues":[]} - if ($loopMode) { + if ($loopMode) + { $totalResults = $result.total Write-Debug "[Get-JiraIssue] Paging through all issues (loop mode)" $allIssues = New-Object -TypeName System.Collections.ArrayList - for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) { + for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) + { $percentComplete = ($i / $totalResults) * 100 Write-Progress -Activity 'Get-JiraIssue' -Status "Obtaining issues ($i - $($i + $PageSize))..." -PercentComplete $percentComplete Write-Debug "[Get-JiraIssue] Obtaining issues $i - $($i + $PageSize)..." $thisSection = Get-JiraIssue -Query $Query -StartIndex $i -MaxResults $PageSize -Credential $Credential - foreach ($t in $thisSection) { + foreach ($t in $thisSection) + { [void] $allIssues.Add($t) } } Write-Progress -Activity 'Get-JiraIssue' -Status 'Obtaining issues' -Completed Write-Output ($allIssues.ToArray()) } - elseif ($result.total -gt 0) { + elseif ($result.total -gt 0) + { Write-Debug "[Get-JiraIssue] Converting REST result to Jira issue" $obj = ConvertTo-JiraIssue -InputObject $result.issues Write-Debug "[Get-JiraIssue] Outputting result" Write-Output $obj } - else { + else + { Write-Debug "[Get-JiraIssue] No results were found for the specified query" Write-Verbose "No results were found for the query [$Query]" } } - else { + else + { Write-Debug "[Get-JiraIssue] Invoke-JiraMethod returned no results" } } - elseif ($PSCmdlet.ParameterSetName -eq 'ByFilter') { + elseif ($PSCmdlet.ParameterSetName -eq 'ByFilter') + { $filterObj = Get-JiraFilter -InputObject $Filter -Credential $Credential - if ($filterObj) { + if ($filterObj) + { $jql = $filterObj.JQL Write-Debug "[Get-JiraIssue] Invoking myself with filter JQL: [$jql]" @@ -194,28 +217,34 @@ function Get-JiraIssue { # was not supplied as a parameter. We don't want to explicitly # invoke this method recursively with a MaxResults value of 1 # if it wasn't initially provided to us. - if ($loopMode) { + if ($loopMode) + { $result = Get-JiraIssue -Query $jql -Credential $Credential } - else { + else + { $result = Get-JiraIssue -Query $jql -Credential $Credential -MaxResults $MaxResults } - if ($result) { + if ($result) + { Write-Debug "[Get-JiraIssue] Returned from invoking myself; outputting results" Write-Output $result } - else { + else + { Write-Debug "[Get-JiraIssue] Returned from invoking myself, but no results were found" } } - else { + else + { Write-Debug "[Get-JiraIssue] Unable to identify filter [$Filter]" Write-Error "Unable to identify filter [$Filter]. Check Get-JiraFilter for more details." } } } - end { + end + { Write-Debug "[Get-JiraIssue] Complete" } } diff --git a/PSJira/Public/Get-JiraIssueComment.ps1 b/PSJira/Public/Get-JiraIssueComment.ps1 index abf6cdf2..cc4dd973 100644 --- a/PSJira/Public/Get-JiraIssueComment.ps1 +++ b/PSJira/Public/Get-JiraIssueComment.ps1 @@ -1,4 +1,5 @@ -function Get-JiraIssueComment { +function Get-JiraIssueComment +{ <# .Synopsis Returns comments on an issue in JIRA. @@ -58,11 +59,15 @@ function Get-JiraIssueComment { Write-Debug "Outputting results" Write-Output $obj - } else { + } + else + { Write-Debug "Result appears to be in an unexpected format. Outputting raw result." Write-Output $result } - } else { + } + else + { Write-Debug "Invoke-JiraMethod returned no results to output." } } @@ -72,5 +77,3 @@ function Get-JiraIssueComment { Write-Debug "Completed Get-JiraIssueComment" } } - - diff --git a/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 b/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 index 216b7642..9a797eaf 100644 --- a/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 +++ b/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 @@ -24,12 +24,12 @@ function Get-JiraIssueCreateMetadata param( # Project ID or key of the reference issue. [Parameter(Mandatory = $true, - Position = 0)] + Position = 0)] [String] $Project, # Issue type ID or name. [Parameter(Mandatory = $true, - Position = 1)] + Position = 1)] [String] $IssueType, # Path of the file with the configuration. @@ -47,7 +47,8 @@ function Get-JiraIssueCreateMetadata try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraIssueCreateMetadata] Encountered an error reading the Jira server." throw $err @@ -62,7 +63,9 @@ function Get-JiraIssueCreateMetadata { $projectId = $projectObj.Id $uri = "${uri}projectIds=$projectId&" - } else { + } + else + { throw "No project was found for the given Project [$Project]. Use Get-JiraProject for more information on this issue." } @@ -72,7 +75,9 @@ function Get-JiraIssueCreateMetadata { $issueTypeId = $issueTypeObj.Id $uri = "${uri}issuetypeIds=$issueTypeId&" - } else { + } + else + { throw "No issue types were found for the given IssueType [$IssueType]. Use Get-JiraIssueType for more information on this issue." } @@ -90,7 +95,9 @@ function Get-JiraIssueCreateMetadata { Write-Debug "[Get-JiraIssueCreateMetadata] No project results were found. Throwing exception." throw "No projects were found for the given project [$Project]. Use Get-JiraProject for more details." - } elseif (@($jiraResult.projects).Count -gt 1) { + } + elseif (@($jiraResult.projects).Count -gt 1) + { Write-Debug "[Get-JiraIssueCreateMetadata] Multiple project results were found. Throwing exception." throw "Multiple projects were found for the given project [$Project]. Refine the parameters to return only one project." } @@ -104,7 +111,9 @@ function Get-JiraIssueCreateMetadata { Write-Debug "[Get-JiraIssueCreateMetadata] No issue type results were found. Throwing exception." throw "No issue types were found for the given issue type [$IssueType]. Use Get-JiraIssueType for more details." - } elseif (@($jiraResult.projects.issuetypes).Count -gt 1) { + } + elseif (@($jiraResult.projects.issuetypes).Count -gt 1) + { Write-Debug "[Get-JiraIssueCreateMetadata] Multiple issue type results were found. Throwing exception." throw "Multiple issue types were found for the given issue type [$IssueType]. Refine the parameters to return only one issue type." } @@ -115,11 +124,11 @@ function Get-JiraIssueCreateMetadata Write-Debug "Outputting results" Write-Output $obj -# Write-Output $jiraResult - } else { + # Write-Output $jiraResult + } + else + { Write-Debug "[Get-JiraIssueCreateMetadata] No results were returned from JIRA." } } } - - diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 index 0cfe992a..5691ee0c 100644 --- a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 +++ b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 @@ -24,7 +24,7 @@ function Get-JiraIssueEditMetadata param( # Issue id or key of the reference issue. [Parameter(Mandatory = $true, - Position = 0)] + Position = 0)] [String] $Issue, # Path of the file with the configuration. @@ -42,7 +42,8 @@ function Get-JiraIssueEditMetadata try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraIssueEditMetadata] Encountered an error reading the Jira server." throw $err @@ -63,7 +64,9 @@ function Get-JiraIssueEditMetadata { Write-Debug "[Get-JiraIssueEditMetadata] No project results were found. Throwing exception." throw "No projects were found for the given project [$Project]. Use Get-JiraProject for more details." - } elseif (@($jiraResult.projects).Count -gt 1) { + } + elseif (@($jiraResult.projects).Count -gt 1) + { Write-Debug "[Get-JiraIssueEditMetadata] Multiple project results were found. Throwing exception." throw "Multiple projects were found for the given project [$Project]. Refine the parameters to return only one project." } @@ -77,7 +80,9 @@ function Get-JiraIssueEditMetadata { Write-Debug "[Get-JiraIssueEditMetadata] No issue type results were found. Throwing exception." throw "No issue types were found for the given issue type [$IssueType]. Use Get-JiraIssueType for more details." - } elseif (@($jiraResult.projects.issuetypes).Count -gt 1) { + } + elseif (@($jiraResult.projects.issuetypes).Count -gt 1) + { Write-Debug "[Get-JiraIssueEditMetadata] Multiple issue type results were found. Throwing exception." throw "Multiple issue types were found for the given issue type [$IssueType]. Refine the parameters to return only one issue type." } @@ -88,8 +93,10 @@ function Get-JiraIssueEditMetadata Write-Debug "Outputting results" Write-Output $obj -# Write-Output $jiraResult - } else { + # Write-Output $jiraResult + } + else + { Write-Debug "[Get-JiraIssueEditMetadata] No results were returned from JIRA." } } diff --git a/PSJira/Public/Get-JiraIssueType.ps1 b/PSJira/Public/Get-JiraIssueType.ps1 index 450d38f8..525cf4a5 100644 --- a/PSJira/Public/Get-JiraIssueType.ps1 +++ b/PSJira/Public/Get-JiraIssueType.ps1 @@ -4,8 +4,8 @@ param( # The Issue Type name or ID to search. [Parameter(Mandatory = $false, - Position = 0, - ValueFromRemainingArguments = $true)] + Position = 0, + ValueFromRemainingArguments = $true)] [String[]] $IssueType, # Credentials to use to connect to JIRA. @@ -20,7 +20,8 @@ try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraIssueType] Encountered an error reading the Jira server." throw $err @@ -44,20 +45,26 @@ { Write-Debug "[Get-JiraIssueType] Found results; outputting" Write-Output $thisIssueType - } else { + } + else + { Write-Debug "[Get-JiraIssueType] No results were found for issue type by name. Searching for issue type (id=[$i])" $thisIssueType = $allIssueTypes | Where-Object -FilterScript {$_.Id -eq $i} if ($thisIssueType) { Write-Debug "[Get-JiraIssueType] Found results; outputting" Write-Output $thisIssueType - } else { + } + else + { Write-Debug "[Get-JiraIssueType] No results were found for issue type by ID. This issue type appears to be unknown." Write-Verbose "Unable to identify Jira issue type [$i]" } } } - } else { + } + else + { Write-Debug "[Get-JiraIssueType] No IssueType was supplied. Outputting all issues." Write-Output $allIssueTypes } diff --git a/PSJira/Public/Get-JiraPriority.ps1 b/PSJira/Public/Get-JiraPriority.ps1 index 835f9a6e..9765c512 100644 --- a/PSJira/Public/Get-JiraPriority.ps1 +++ b/PSJira/Public/Get-JiraPriority.ps1 @@ -36,7 +36,9 @@ function Get-JiraPriority Write-Debug "[Get-JiraPriority] Outputting result" Write-Output $obj - } else { + } + else + { Write-Debug "[Get-JiraPriority] Invoke-JiraMethod returned no results to output." } } @@ -46,5 +48,3 @@ function Get-JiraPriority Write-Debug "[Get-JiraPriority] Complete." } } - - diff --git a/PSJira/Public/Get-JiraProject.ps1 b/PSJira/Public/Get-JiraProject.ps1 index 2b63c687..9c437d2d 100644 --- a/PSJira/Public/Get-JiraProject.ps1 +++ b/PSJira/Public/Get-JiraProject.ps1 @@ -28,7 +28,7 @@ function Get-JiraProject param( # The Project ID or project key of a project to search. [Parameter(Mandatory = $false, - Position = 0)] + Position = 0)] [String[]] $Project, # Credentials to use to connect to JIRA. @@ -43,7 +43,8 @@ function Get-JiraProject try { $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Get-JiraProject] Encountered an error reading the Jira server." throw $err @@ -71,12 +72,16 @@ function Get-JiraProject Write-Debug "[Get-JiraProject] Outputting result" Write-Output $obj - } else { + } + else + { Write-Debug "[Get-JiraProject] No results were returned from Jira" Write-Debug "[Get-JiraProject] No results were returned from Jira for project [$p]" } } - } else { + } + else + { Write-Debug "[Get-JiraProject] Attempting to search for all projects" $thisUri = "$uri" @@ -89,7 +94,9 @@ function Get-JiraProject Write-Debug "[Get-JiraProject] Outputting result" Write-Output $obj - } else { + } + else + { Write-Debug "[Get-JiraProject] No results were returned from Jira" Write-Debug "[Get-JiraProject] No project results were returned from Jira" } diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/PSJira/Public/Get-JiraRemoteLink.ps1 index 096935c4..df3ad855 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/PSJira/Public/Get-JiraRemoteLink.ps1 @@ -1,4 +1,5 @@ -function Get-JiraRemoteLink { +function Get-JiraRemoteLink +{ <# .Synopsis Returns a remote link from a Jira issue @@ -35,7 +36,8 @@ function Get-JiraRemoteLink { [PSCredential] $Credential ) - Begin { + Begin + { Write-Debug "[Get-JiraRemoteLink] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop @@ -45,32 +47,39 @@ function Get-JiraRemoteLink { $linkUrl = "$server/rest/api/latest/issue/{0}/remotelink" } - Process { - foreach ($k in $Issue) { + Process + { + foreach ($k in $Issue) + { Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" $thisUrl = $linkUrl -f $k if ($linkId) - { $thisUrl += "/$l" } + { + $thisUrl += "/$l" + } Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential - if ($result) { + if ($result) + { Write-Debug "[Get-JiraRemoteLink] Converting results to PSJira.Group" $obj = ConvertTo-JiraLink -InputObject $result Write-Debug "[Get-JiraRemoteLink] Outputting results" Write-Output $obj } - else { + else + { Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" Write-Verbose "No results were returned from JIRA." } } } - End { + End + { Write-Debug "[Get-JiraRemoteLink] Complete" } } diff --git a/PSJira/Public/Get-JiraSession.ps1 b/PSJira/Public/Get-JiraSession.ps1 index 8b45f889..10f9b60a 100644 --- a/PSJira/Public/Get-JiraSession.ps1 +++ b/PSJira/Public/Get-JiraSession.ps1 @@ -27,15 +27,17 @@ function Get-JiraSession { Write-Debug "[Get-JiraSession] A Session object is saved; outputting" Write-Output $MyInvocation.MyCommand.Module.PrivateData.Session - } else { + } + else + { Write-Debug "[Get-JiraSession] No Session objects are saved" Write-Verbose "No Jira sessions have been saved." } - } else { + } + else + { Write-Debug "[Get-JiraSession] No module private data is defined. No saved sessions exist." Write-Verbose "No Jira sessions have been saved." } } } - - diff --git a/PSJira/Public/Get-JiraUser.ps1 b/PSJira/Public/Get-JiraUser.ps1 index 4e72120b..5d101c61 100644 --- a/PSJira/Public/Get-JiraUser.ps1 +++ b/PSJira/Public/Get-JiraUser.ps1 @@ -23,16 +23,16 @@ function Get-JiraUser # Username, name, or e-mail address of the user. Any of these should # return search results from Jira. [Parameter(ParameterSetName = 'ByUserName', - Mandatory = $true, - Position = 0)] + Mandatory = $true, + Position = 0)] [ValidateNotNullOrEmpty()] - [Alias('User','Name')] + [Alias('User', 'Name')] [String[]] $UserName, # User Object of the user. [Parameter(ParameterSetName = 'ByInputObject', - Mandatory = $true, - Position = 0)] + Mandatory = $true, + Position = 0)] [Object[]] $InputObject, # Include inactive users in the search @@ -88,16 +88,22 @@ function Get-JiraUser Write-Debug "[Get-JiraUser] Converting result to PSJira.User object" $thisUserObject = ConvertTo-JiraUser -InputObject $thisUserResult Write-Output $thisUserObject - } else { + } + else + { Write-Debug "[Get-JiraUser] User [$r] could not be found in JIRA." } } - } else { + } + else + { Write-Debug "[Get-JiraUser] JIRA returned no results." Write-Verbose "JIRA returned no results for user [$u]." } } - } else { + } + else + { foreach ($i in $InputObject) { Write-Debug "[Get-JiraUser] Processing InputObject [$i]" @@ -105,7 +111,9 @@ function Get-JiraUser { Write-Debug "[Get-JiraUser] User parameter is a PSJira.User object" $thisUserName = $i.Name - } else { + } + else + { $thisUserName = $i.ToString() Write-Debug "[Get-JiraUser] Username is assumed to be [$thisUserName] via ToString()" } @@ -123,5 +131,3 @@ function Get-JiraUser Write-Debug "[Get-JiraUser] Complete" } } - - diff --git a/PSJira/Public/Invoke-JiraIssueTransition.ps1 b/PSJira/Public/Invoke-JiraIssueTransition.ps1 index 2e304ed6..a9bff1ad 100644 --- a/PSJira/Public/Invoke-JiraIssueTransition.ps1 +++ b/PSJira/Public/Invoke-JiraIssueTransition.ps1 @@ -1,4 +1,5 @@ -function Invoke-JiraIssueTransition { +function Invoke-JiraIssueTransition +{ <# .Synopsis Performs an issue transition on a JIRA issue, changing its status @@ -47,29 +48,36 @@ function Invoke-JiraIssueTransition { [System.Management.Automation.PSCredential] $Credential ) - begin { + begin + { # We can't validate pipeline input here, since pipeline input doesn't exist in the Begin block. } - process { + process + { Write-Debug "[Invoke-JiraIssueTransition] Obtaining a reference to Jira issue [$Issue]" $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential - if (-not $issueObj) { + if (-not $issueObj) + { Write-Debug "[Invoke-JiraIssueTransition] No Jira issues were found for parameter [$Issue]. An exception will be thrown." throw "Unable to identify Jira issue [$Issue]. Use Get-JiraIssue for more information." } Write-Debug "[Invoke-JiraIssueTransition] Checking Transition parameter" - if ($Transition.PSObject.TypeNames[0] -eq 'PSJira.Transition') { + if ($Transition.PSObject.TypeNames[0] -eq 'PSJira.Transition') + { Write-Debug "[Invoke-JiraIssueTransition] Transition parameter is a PSJira.Transition object" $transitionId = $Transition.ID } - else { + else + { Write-Debug "[Invoke-JiraIssueTransition] Attempting to cast Transition parameter [$Transition] as int for transition ID" - try { + try + { $transitionId = [int] "$Transition" - } catch { + } catch + { $err = $_ Write-Debug "[Invoke-JiraIssueTransition] Encountered an error converting transition to Int. An exception will be thrown." throw $err @@ -77,10 +85,12 @@ function Invoke-JiraIssueTransition { } Write-Debug "[Invoke-JiraIssueTransition] Checking that the issue can perform the given transition" - if (($issueObj.Transition | Select-Object -ExpandProperty ID) -contains $transitionId) { + if (($issueObj.Transition | Select-Object -ExpandProperty ID) -contains $transitionId) + { Write-Debug "[Invoke-JiraIssueTransition] Transition [$transitionId] is valid for issue [$issueObj]" } - else { + else + { Write-Debug "[Invoke-JiraIssueTransition] Transition [$transitionId] is not valid for issue [$issueObj]. An exception will be thrown." throw "The specified Jira issue cannot perform transition [$transitionId]. Check the issue's Transition property and provide a transition valid for its current state." } @@ -99,21 +109,22 @@ function Invoke-JiraIssueTransition { Write-Debug "[Invoke-JiraIssueTransition] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $transitionUrl -Body $json -Credential $Credential - if ($result) { + if ($result) + { # JIRA doesn't typically return results here unless they contain errors, which are handled within Invoke-JiraMethod. # If something does come out, let us know. Write-Debug "[Invoke-JiraIssueTransition] Outputting raw results from JIRA." Write-Warning "JIRA returned unexpected results, which are provided below." Write-Output $result } - else { + else + { Write-Debug "[Invoke-JiraIssueTransition] No results were returned from JIRA." } } - end { + end + { Write-Debug "Complete" } } - - diff --git a/PSJira/Public/New-JiraGroup.ps1 b/PSJira/Public/New-JiraGroup.ps1 index f5574e92..750c2715 100644 --- a/PSJira/Public/New-JiraGroup.ps1 +++ b/PSJira/Public/New-JiraGroup.ps1 @@ -1,4 +1,5 @@ -function New-JiraGroup { +function New-JiraGroup +{ <# .Synopsis Creates a new group in JIRA @@ -26,12 +27,15 @@ [PSCredential] $Credential ) - begin { + begin + { Write-Debug "[New-JiraGroup] Reading information from config file" - try { + try + { Write-Debug "[New-JiraGroup] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[New-JiraGroup] Encountered an error reading configuration data." throw $err @@ -40,7 +44,8 @@ $restUrl = "$server/rest/api/latest/group" } - process { + process + { Write-Debug "[New-JiraGroup] Defining properties" $props = @{ "name" = $GroupName; @@ -52,11 +57,13 @@ Write-Debug "[New-JiraGroup] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $restUrl -Body $json -Credential $Credential - if ($result) { + if ($result) + { Write-Debug "[New-JiraGroup] Converting output object into a Jira user and outputting" ConvertTo-JiraGroup -InputObject $result } - else { + else + { Write-Debug "[New-JiraGroup] Jira returned no results to output." } } diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index ee205f68..6cdedfd0 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -1,4 +1,5 @@ -function New-JiraIssue { +function New-JiraIssue +{ <# .Synopsis Creates an issue in JIRA @@ -71,15 +72,18 @@ function New-JiraIssue { [PSCredential] $Credential ) - begin { + begin + { Write-Debug "[New-JiraIssue] Reading information from config file" - try { + try + { Write-Debug "[New-JiraIssue] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop Write-Debug "[New-JiraIssue] Reading Jira issue create metadata" $createmeta = Get-JiraIssueCreateMetadata -Project $Project -IssueType $IssueType -ConfigFile $ConfigFile -Credential $Credential -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[New-JiraIssue] Encountered an error reading configuration data." throw $err @@ -89,18 +93,21 @@ function New-JiraIssue { Write-Debug "[New-JiraIssue] Obtaining a reference to Jira project [$Project]" $ProjectObj = Get-JiraProject -Project $Project -Credential $Credential - if (-not ($ProjectObj)) { + if (-not ($ProjectObj)) + { throw "Unable to identify Jira project [$Project]. Use Get-JiraProject for more information." } Write-Debug "[New-JiraIssue] Obtaining a reference to Jira issue type [$IssueType]" $IssueTypeObj = Get-JiraIssueType -IssueType $IssueType -Credential $Credential - if (-not ($IssueTypeObj)) { + if (-not ($IssueTypeObj)) + { throw "Unable to identify Jira issue type [$IssueType]. Use Get-JiraIssueType for more information." } } - process { + process + { $ProjectParam = New-Object -TypeName PSObject -Property @{"id" = $ProjectObj.Id} $IssueTypeParam = New-Object -TypeName PSObject -Property @{"id" = [String] $IssueTypeObj.Id} @@ -109,40 +116,48 @@ function New-JiraIssue { "summary" = $Summary; "issuetype" = $IssueTypeParam; } - if ($Priority) { + if ($Priority) + { $props.priority = New-Object -TypeName PSObject -Property @{"id" = [String] $Priority} } - if ($Description) { + if ($Description) + { $props.description = $Description } - if ($Reporter) { + if ($Reporter) + { $props.reporter = New-Object -TypeName PSObject -Property @{"name" = $Reporter} } - if ($Parent) { + if ($Parent) + { $props.parent = New-Object -TypeName PSObject -Property @{"key" = $Parent} } - if ($Labels) { + if ($Labels) + { [void] $props.Add('labels', $Labels) } Write-Debug "[New-JiraIssue] Processing Fields parameter" - foreach ($k in $Fields.Keys) { + foreach ($k in $Fields.Keys) + { $name = $k $value = $Fields.$k Write-Debug "[New-JiraIssue] Attempting to identify field (name=[$name], value=[$value])" $f = Get-JiraField -Field $name -Credential $Credential - if ($f) { + if ($f) + { $id = $f.ID Write-Debug "[New-JiraIssue] Field [$name] was identified as ID [$id]" $props.$id = $value } - else { + else + { Write-Debug "[New-JiraIssue] Field [$name] could not be identified in Jira" throw "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." } @@ -150,22 +165,29 @@ function New-JiraIssue { Write-Verbose "Checking Jira createmeta to make sure all required fields are provided" Write-Debug "[New-JiraIssue] Testing Jira createmeta" - foreach ($c in $createmeta) { - if ($c.Required) { - if ($props.ContainsKey($c.Id)) { + foreach ($c in $createmeta) + { + if ($c.Required) + { + if ($props.ContainsKey($c.Id)) + { Write-Debug "[New-JiraIssue] Required field (id=[$($c.Id)], name=[$($c.Name)]) was provided (value=[$($props.$($c.Id))])" } - else { + else + { Write-Debug "[New-JiraIssue] Required field (id=[$($c.Id)], name=[$($c.Name)]) was NOT provided. Writing error." - if ($c.Id -eq 'Reporter') { + if ($c.Id -eq 'Reporter') + { throw "Jira's metadata for project [$Project] and issue type [$IssueType] requires a reporter. Provide a value for the -Reporter parameter when creating an issue." } - else { + else + { throw "Jira's metadata for project [$Project] and issue type [$IssueType] specifies that a field is required that was not provided (name=[$($c.Name)], id=[$($c.Id)]). You must supply this field via the -Fields parameter. Use Get-JiraIssueCreateMetadata for more information." } } } - else { + else + { Write-Debug "[New-JiraIssue] Non-required field (id=[$($c.Id)], name=[$($c.Name)])" } } @@ -181,7 +203,8 @@ function New-JiraIssue { Write-Debug "[New-JiraIssue] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $issueURL -Body $json -Credential $Credential - if ($result) { + if ($result) + { # REST result will look something like this: # {"id":"12345","key":"IT-3676","self":"http://jiraserver.example.com/rest/api/latest/issue/12345"} @@ -191,12 +214,14 @@ function New-JiraIssue { Write-Debug "[New-JiraIssue] Writing output from New-JiraIssue" Write-Output $getResult } - else { + else + { Write-Debug "[New-JiraIssue] Jira returned no results to output." } } - end { + end + { Write-Debug "[New-JiraIssue] Completing New-JiraIssue" } } diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index f8cf2fac..becf799e 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -26,7 +26,7 @@ function New-JiraSession param( # Credentials to use to connect to JIRA. [Parameter(Mandatory = $true, - Position = 0)] + Position = 0)] [System.Management.Automation.PSCredential] $Credential ) @@ -36,7 +36,8 @@ function New-JiraSession { Write-Debug "[New-JiraSession] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[New-JiraSession] Encountered an error reading configuration data." throw $err @@ -71,7 +72,9 @@ function New-JiraSession { Write-Debug "[New-JiraSession] Adding session result to existing module PrivateData" $MyInvocation.MyCommand.Module.PrivateData.Session = $result; - } else { + } + else + { Write-Debug "[New-JiraSession] Creating module PrivateData" $MyInvocation.MyCommand.Module.PrivateData = @{ 'Session' = $result; @@ -80,7 +83,8 @@ function New-JiraSession Write-Debug "[New-JiraSession] Outputting result" Write-Output $result - } catch { + } catch + { $err = $_ $webResponse = $err.Exception.Response Write-Debug "[New-JiraSession] Encountered an exception from the Jira server: $err" @@ -98,5 +102,3 @@ function New-JiraSession } } } - - diff --git a/PSJira/Public/New-JiraUser.ps1 b/PSJira/Public/New-JiraUser.ps1 index e8db78b2..756f74b6 100644 --- a/PSJira/Public/New-JiraUser.ps1 +++ b/PSJira/Public/New-JiraUser.ps1 @@ -1,4 +1,5 @@ -function New-JiraUser { +function New-JiraUser +{ <# .Synopsis Creates a new user in JIRA @@ -45,12 +46,15 @@ function New-JiraUser { [PSCredential] $Credential ) - begin { + begin + { Write-Debug "[New-JiraUser] Reading information from config file" - try { + try + { Write-Debug "[New-JiraUser] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[New-JiraUser] Encountered an error reading configuration data." throw $err @@ -59,17 +63,20 @@ function New-JiraUser { $userURL = "$server/rest/api/latest/user" } - process { + process + { Write-Debug "[New-JiraUser] Defining properties" $props = @{ "name" = $UserName; "emailAddress" = $EmailAddress; } - if ($DisplayName) { + if ($DisplayName) + { $props.displayName = $DisplayName } - else { + else + { Write-Debug "[New-JiraUser] DisplayName was not specified; defaulting to UserName parameter [$UserName]" $props.displayName = $UserName } @@ -83,25 +90,28 @@ function New-JiraUser { Write-Debug "[New-JiraUser] Preparing for blastoff!" $result = Invoke-JiraMethod -Method Post -URI $userURL -Body $json -Credential $Credential - if ($result) { - if ($result.errors) { + if ($result) + { + if ($result.errors) + { Write-Debug "[New-JiraUser] Jira return an error result object." $keys = (Get-Member -InputObject $result.errors | Where-Object -FilterScript {$_.MemberType -eq 'NoteProperty'}).Name - foreach ($k in $keys) { + foreach ($k in $keys) + { Write-Error "Jira encountered an error: [$($k)] - $($result.errors.$k)" } } - else { + else + { # OK Write-Debug "[New-JiraUser] Converting output object into a Jira user and outputting" ConvertTo-JiraUser -InputObject $result } } - else { + else + { Write-Debug "[New-JiraUser] Jira returned no results to output." } } } - - diff --git a/PSJira/Public/Remove-JiraGroup.ps1 b/PSJira/Public/Remove-JiraGroup.ps1 index c8d71a24..cc3e9937 100644 --- a/PSJira/Public/Remove-JiraGroup.ps1 +++ b/PSJira/Public/Remove-JiraGroup.ps1 @@ -1,4 +1,5 @@ -function Remove-JiraGroup { +function Remove-JiraGroup +{ <# .Synopsis Removes an existing group from JIRA @@ -33,12 +34,15 @@ [Switch] $Force ) - begin { + begin + { Write-Debug "[Remove-JiraGroup] Reading information from config file" - try { + try + { Write-Debug "[Remove-JiraGroup] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Remove-JiraGroup] Encountered an error reading configuration data." throw $err @@ -46,36 +50,44 @@ $restUrl = "$server/rest/api/latest/group?groupname={0}" - if ($Force) { + if ($Force) + { Write-Debug "[Remove-JiraGroup] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" $oldConfirmPreference = $ConfirmPreference $ConfirmPreference = 'None' } } - process { - foreach ($g in $Group) { + process + { + foreach ($g in $Group) + { Write-Debug "[Remove-JiraGroup] Obtaining reference to group [$g]" $groupObj = Get-JiraGroup -InputObject $g -Credential $Credential - if ($groupObj) { + if ($groupObj) + { $thisUrl = $restUrl -f $groupObj.Name Write-Debug "[Remove-JiraGroup] Group URL: [$thisUrl]" Write-Debug "[Remove-JiraGroup] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess($groupObj.Name, "Remove group [$groupObj] from JIRA")) { + if ($PSCmdlet.ShouldProcess($groupObj.Name, "Remove group [$groupObj] from JIRA")) + { Write-Debug "[Remove-JiraGroup] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential } - else { + else + { Write-Debug "[Remove-JiraGroup] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } } } } - end { - if ($Force) { + end + { + if ($Force) + { Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" $ConfirmPreference = $oldConfirmPreference } diff --git a/PSJira/Public/Remove-JiraGroupMember.ps1 b/PSJira/Public/Remove-JiraGroupMember.ps1 index f3c07ee0..cde25b6d 100644 --- a/PSJira/Public/Remove-JiraGroupMember.ps1 +++ b/PSJira/Public/Remove-JiraGroupMember.ps1 @@ -1,4 +1,5 @@ -function Remove-JiraGroupMember { +function Remove-JiraGroupMember +{ <# .Synopsis Removes a user from a JIRA group @@ -49,13 +50,15 @@ function Remove-JiraGroupMember { [Switch] $Force ) - begin { + begin + { Write-Debug "[Remove-JiraGroupMember] Reading information from config file" try { Write-Debug "[Remove-JiraGroupMember] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Remove-JiraGroupMember] Encountered an error reading configuration data." throw $err @@ -63,69 +66,84 @@ function Remove-JiraGroupMember { $restUrl = "$server/rest/api/latest/group/user?groupname={0}&username={1}" - if ($Force) { + if ($Force) + { Write-Debug "[Remove-JiraGroupMember] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" $oldConfirmPreference = $ConfirmPreference $ConfirmPreference = 'None' } } - process { - foreach ($g in $Group) { + process + { + foreach ($g in $Group) + { Write-Debug "[Remove-JiraGroupMember] Obtaining reference to group [$g]" $groupObj = Get-JiraGroup -InputObject $g -Credential $Credential - if ($groupObj) { + if ($groupObj) + { Write-Debug "[Remove-JiraGroupMember] Obtaining members of group [$g]" $groupMembers = Get-JiraGroupMember -Group $g -Credential $Credential | Select-Object -ExpandProperty Name - foreach ($u in $User) { + foreach ($u in $User) + { Write-Debug "[Remove-JiraGroupMember] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) { + if ($userObj) + { Write-Debug "[Remove-JiraGroupMember] Retrieved user reference [$userObj]" - if ($groupMembers -contains $userObj.Name) { + if ($groupMembers -contains $userObj.Name) + { $thisRestUrl = $restUrl -f $groupObj.Name, $userObj.Name Write-Debug "[Remove-JiraGroupMember] REST URI: [$thisRestUrl]" Write-Debug "[Remove-JiraGroupMember] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess("$groupObj", "Remove $userObj from group")) { + if ($PSCmdlet.ShouldProcess("$groupObj", "Remove $userObj from group")) + { Write-Debug "[Remove-JiraGroupMember] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisRestUrl -Credential $Credential } - else { + else + { Write-Debug "[Remove-JiraGroupMember] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } } - else { + else + { Write-Debug "[Remove-JiraGroupMember] User [$u] is not currently a member of group [$g]" Write-Verbose "User [$u] is not currently a member of group [$g]" } } - else { + else + { Write-Debug "[Remove-JiraGroupMember] Could not identify user [$u]. Writing error message." Write-Error "Unable to identify user [$u]. Check the spelling of this user and ensure that you can access it via Get-JiraUser." } } - if ($PassThru) { + if ($PassThru) + { Write-Debug "[Remove-JiraGroupMember] -PassThru specified. Obtaining a final reference to group [$g]" $groupObjNew = Get-JiraGroup -InputObject $g -Credential $Credential Write-Debug "[Remove-JiraGroupMember] Outputting group [$groupObjNew]" Write-Output $groupObjNew } } - else { + else + { Write-Debug "[Remove-JiraGroupMember] Could not identify group [$g]" Write-Error "Unable to identify group [$g]. Check the spelling of this group and ensure that you can access it via Get-JiraGroup." } } } - end { - if ($Force) { + end + { + if ($Force) + { Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" $ConfirmPreference = $oldConfirmPreference } @@ -133,7 +151,3 @@ function Remove-JiraGroupMember { Write-Debug "[Remove-JiraGroupMember] Complete" } } - - - - diff --git a/PSJira/Public/Remove-JiraRemoteLink.ps1 b/PSJira/Public/Remove-JiraRemoteLink.ps1 index d7f689dd..d6163ccd 100644 --- a/PSJira/Public/Remove-JiraRemoteLink.ps1 +++ b/PSJira/Public/Remove-JiraRemoteLink.ps1 @@ -1,5 +1,6 @@ function Remove-JiraRemoteLink -{<# +{ + <# .Synopsis Removes a remote link from a JIRA issue .DESCRIPTION @@ -16,13 +17,13 @@ function Remove-JiraRemoteLink This function returns no output. #> [CmdletBinding(SupportsShouldProcess = $true, - ConfirmImpact = 'High')] + ConfirmImpact = 'High')] param( # Issue from which to delete a remote link. [Parameter(ValueFromPipelineByPropertyName = $true, - ValueFromPipeline = $true, - Mandatory = $true, - Position = 0 + ValueFromPipeline = $true, + Mandatory = $true, + Position = 0 )] [Alias("Key")] [Object[]] $Issue, @@ -46,7 +47,8 @@ function Remove-JiraRemoteLink { Write-Debug "[Remove-JiraRemoteLink] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Remove-JiraRemoteLink] Encountered an error reading configuration data." throw $err @@ -72,7 +74,7 @@ function Remove-JiraRemoteLink foreach ($l in $LinkId) { - $thisUrl = $restUrl -f $k,$l + $thisUrl = $restUrl -f $k, $l Write-Debug "[Remove-JiraRemoteLink] RemoteLink URL: [$thisUrl]" Write-Debug "[Remove-JiraRemoteLink] Checking for -WhatIf and Confirm" @@ -80,7 +82,9 @@ function Remove-JiraRemoteLink { Write-Debug "[Remove-JiraRemoteLink] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential - } else { + } + else + { Write-Debug "[Remove-JiraRemoteLink] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } } diff --git a/PSJira/Public/Remove-JiraSession.ps1 b/PSJira/Public/Remove-JiraSession.ps1 index d5a34c0d..e54c8d69 100644 --- a/PSJira/Public/Remove-JiraSession.ps1 +++ b/PSJira/Public/Remove-JiraSession.ps1 @@ -31,8 +31,8 @@ function Remove-JiraSession param( # A Jira session to be closed. If not specified, this function will use a saved session. [Parameter(Mandatory = $false, - Position = 0, - ValueFromPipeline = $true)] + Position = 0, + ValueFromPipeline = $true)] [Object] $Session ) @@ -42,7 +42,8 @@ function Remove-JiraSession { Write-Debug "[Remove-JiraSession] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Remove-JiraSession] Encountered an error reading configuration data." throw $err @@ -63,11 +64,15 @@ function Remove-JiraSession if ((Get-Member -InputObject $Session).TypeName -eq 'PSJira.Session') { Write-Debug "[Remove-JiraSession] Successfully parsed Session parameter as a PSJira.Session object" - } else { + } + else + { Write-Debug "[Remove-JiraSession] Session parameter is not a PSJira.Session object. Throwing exception" throw "Unable to parse parameter [$Session] as a PSJira.Session object" } - } else { + } + else + { Write-Debug "[Remove-JiraSession] Session parameter was not supplied. Checking for saved session in module PrivateData" $Session = Get-JiraSession } @@ -85,13 +90,16 @@ function Remove-JiraSession { Write-Debug "[Remove-JiraSession] Removing session from existing module PrivateData" $MyInvocation.MyCommand.Module.PrivateData.Session = $null; - } else { + } + else + { Write-Debug "[Remove-JiraSession] Creating module PrivateData" $MyInvocation.MyCommand.Module.PrivateData = @{ 'Session' = $null; } } - } catch { + } catch + { $err = $_ $webResponse = $err.Exception.Response Write-Debug "[Remove-JiraSession] Encountered an exception from the Jira server: $err" @@ -107,10 +115,10 @@ function Remove-JiraSession $result = ConvertFrom-Json2 -InputObject $body Write-Debug "Converted body from JSON into PSCustomObject (`$result)" } - } else { + } + else + { Write-Verbose "No Jira session is saved." } } } - - diff --git a/PSJira/Public/Remove-JiraUser.ps1 b/PSJira/Public/Remove-JiraUser.ps1 index 24c968a5..ed6eef49 100644 --- a/PSJira/Public/Remove-JiraUser.ps1 +++ b/PSJira/Public/Remove-JiraUser.ps1 @@ -1,4 +1,5 @@ -function Remove-JiraUser { +function Remove-JiraUser +{ <# .Synopsis Removes an existing user from JIRA @@ -36,12 +37,15 @@ function Remove-JiraUser { [Switch] $Force ) - begin { + begin + { Write-Debug "[Remove-JiraUser] Reading information from config file" - try { + try + { Write-Debug "[Remove-JiraUser] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch { + } catch + { $err = $_ Write-Debug "[Remove-JiraUser] Encountered an error reading configuration data." throw $err @@ -49,36 +53,44 @@ function Remove-JiraUser { $userURL = "$server/rest/api/latest/user?username={0}" - if ($Force) { + if ($Force) + { Write-Debug "[Remove-JiraGroup] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" $oldConfirmPreference = $ConfirmPreference $ConfirmPreference = 'None' } } - process { - foreach ($u in $User) { + process + { + foreach ($u in $User) + { Write-Debug "[Remove-JiraUser] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) { + if ($userObj) + { $thisUrl = $userUrl -f $userObj.Name Write-Debug "[Remove-JiraUser] User URL: [$thisUrl]" Write-Debug "[Remove-JiraUser] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess($userObj.Name, 'Completely remove user from JIRA')) { + if ($PSCmdlet.ShouldProcess($userObj.Name, 'Completely remove user from JIRA')) + { Write-Debug "[Remove-JiraUser] Preparing for blastoff!" Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential } - else { + else + { Write-Debug "[Remove-JiraUser] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" } } } } - end { - if ($Force) { + end + { + if ($Force) + { Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" $ConfirmPreference = $oldConfirmPreference } @@ -86,5 +98,3 @@ function Remove-JiraUser { Write-Debug "[Remove-JiraUser] Complete" } } - - diff --git a/PSJira/Public/Set-JiraConfigServer.ps1 b/PSJira/Public/Set-JiraConfigServer.ps1 index 5de6cc84..af226c05 100644 --- a/PSJira/Public/Set-JiraConfigServer.ps1 +++ b/PSJira/Public/Set-JiraConfigServer.ps1 @@ -22,7 +22,7 @@ function Set-JiraConfigServer param( # The base URL of the Jira instance. [Parameter(Mandatory = $true, - Position = 0)] + Position = 0)] [ValidateNotNullOrEmpty()] [Alias('Uri')] [String] $Server, @@ -38,21 +38,23 @@ function Set-JiraConfigServer if (-not ($ConfigFile)) { -# Write-Debug "[Set-JiraConfigServer] ConfigFile was not provided, or provided with a null value" + # Write-Debug "[Set-JiraConfigServer] ConfigFile was not provided, or provided with a null value" # This file should be in $moduleRoot/Functions/Internal, so PSScriptRoot will be $moduleRoot/Functions $moduleFolder = Split-Path -Path $PSScriptRoot -Parent -# Write-Debug "[Set-JiraConfigServer] Module folder: $moduleFolder" + # Write-Debug "[Set-JiraConfigServer] Module folder: $moduleFolder" $ConfigFile = Join-Path -Path $moduleFolder -ChildPath 'config.xml' -# Write-Debug "[Set-JiraConfigServer] Using default config file at [$ConfigFile]" + # Write-Debug "[Set-JiraConfigServer] Using default config file at [$ConfigFile]" } if (-not (Test-Path -Path $ConfigFile)) { -# Write-Debug "[Set-JiraConfigServer] Creating config file '$ConfigFile'" + # Write-Debug "[Set-JiraConfigServer] Creating config file '$ConfigFile'" $xml = [XML] '' - } else { -# Write-Debug "[Set-JiraConfigServer] Loading config file '$ConfigFile'" + } + else + { + # Write-Debug "[Set-JiraConfigServer] Loading config file '$ConfigFile'" $xml = New-Object -TypeName XML $xml.Load($ConfigFile) } @@ -66,35 +68,37 @@ function Set-JiraConfigServer # Check for trailing slash and strip it if necessary $fixedServer = $Server.Trim() - if ($fixedServer.EndsWith('/') -or $fixedServer.EndsWith('\')) { + if ($fixedServer.EndsWith('/') -or $fixedServer.EndsWith('\')) + { $fixedServer = $Server.Substring(0, $Server.Length - 1) } if ($xmlConfig.Server) { -# Write-Debug "[Set-JiraConfigServer] Changing the existing Server element to the provided value '$Server'" + # Write-Debug "[Set-JiraConfigServer] Changing the existing Server element to the provided value '$Server'" $xmlConfig.Server = $fixedServer - } else { -# Write-Debug "[Set-JiraConfigServer] Creating new element Server" + } + else + { + # Write-Debug "[Set-JiraConfigServer] Creating new element Server" $xmlServer = $xml.CreateElement('Server') -# Write-Debug "[Set-JiraConfigServer] Writing InnerText property with provided value '$Server'" + # Write-Debug "[Set-JiraConfigServer] Writing InnerText property with provided value '$Server'" $xmlServer.InnerText = $fixedServer -# Write-Debug "[Set-JiraConfigServer] Adding element to existing XML file" + # Write-Debug "[Set-JiraConfigServer] Adding element to existing XML file" [void] $xmlConfig.AppendChild($xmlServer) } -# Write-Debug "[Set-JiraConfigServer] Saving XML file" + # Write-Debug "[Set-JiraConfigServer] Saving XML file" try { $xml.Save($ConfigFile) - } catch { + } catch + { $err = $_ -# Write-Debug "[Set-JiraConfigServer] Encountered an error saving the XML file" -# Write-Debug "[Set-JiraConfigServer] Throwing exception" + # Write-Debug "[Set-JiraConfigServer] Encountered an error saving the XML file" + # Write-Debug "[Set-JiraConfigServer] Throwing exception" throw $err } -# Write-Debug "[Set-JiraConfigServer] Complete" + # Write-Debug "[Set-JiraConfigServer] Complete" } - - diff --git a/PSJira/Public/Set-JiraIssue.ps1 b/PSJira/Public/Set-JiraIssue.ps1 index f0039922..a6b45931 100644 --- a/PSJira/Public/Set-JiraIssue.ps1 +++ b/PSJira/Public/Set-JiraIssue.ps1 @@ -27,9 +27,9 @@ function Set-JiraIssue param( # Issue key or PSJira.Issue object returned from Get-JiraIssue. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Alias('Key')] [Object[]] $Issue, @@ -87,7 +87,9 @@ function Set-JiraIssue Write-Debug "[Set-JiraIssue] 'Unassigned' String passed. Issue will be assigned to no one." $assigneeString = "" $validAssignee = $true - } else { + } + else + { Write-Debug "[Set-JiraIssue] Attempting to obtain Jira user [$Assignee]" $assigneeObj = Get-JiraUser -InputObject $Assignee -Credential $Credential if ($assigneeObj) @@ -95,7 +97,9 @@ function Set-JiraIssue Write-Debug "[Set-JiraIssue] User found (name=[$($assigneeObj.Name)],RestUrl=[$($assigneeObj.RestUrl)])" $assigneeString = $assigneeObj.Name $validAssignee = $true - } else { + } + else + { Write-Debug "[Set-JiraIssue] Unable to obtain Assignee. Exception will be thrown." throw "Unable to validate Jira user [$Assignee]. Use Get-JiraUser for more details." } @@ -162,7 +166,9 @@ function Set-JiraIssue 'set' = $value; } $actOnIssueUri = $true - } else { + } + else + { Write-Debug "[Set-JiraIssue] Field [$name] could not be identified in Jira" throw "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." } @@ -172,7 +178,7 @@ function Set-JiraIssue if ($validAssignee) { - $assigneeProps = @{ + $assigneeProps = @{ 'name' = $assigneeString; } @@ -217,7 +223,9 @@ function Set-JiraIssue Get-JiraIssue -Key $issueObj.Key -Credential $Credential } - } else { + } + else + { Write-Debug "[Set-JiraIssue] Unable to identify issue [$i]. Writing error message." Write-Error "Unable to identify issue [$i]" } @@ -229,5 +237,3 @@ function Set-JiraIssue Write-Debug "[Set-JiraIssue] Complete" } } - - diff --git a/PSJira/Public/Set-JiraIssueLabel.ps1 b/PSJira/Public/Set-JiraIssueLabel.ps1 index b44f51c6..78671bb3 100644 --- a/PSJira/Public/Set-JiraIssueLabel.ps1 +++ b/PSJira/Public/Set-JiraIssueLabel.ps1 @@ -1,4 +1,5 @@ -function Set-JiraIssueLabel { +function Set-JiraIssueLabel +{ <# .Synopsis Modifies labels on an existing JIRA issue @@ -65,17 +66,21 @@ [Switch] $PassThru ) - begin { + begin + { Write-Debug "[Set-JiraIssueLabel] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } - process { - foreach ($i in $Issue) { + process + { + foreach ($i in $Issue) + { Write-Debug "[Set-JiraIssueLabel] Obtaining reference to issue" $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential - if ($issueObj) { + if ($issueObj) + { $currentLabels = @($issueObj.labels) $url = $issueObj.RestURL $isDirty = $true @@ -88,26 +93,32 @@ # issue object and use the Set verb for everything, so we only # have to make one call to JIRA. - if ($Clear) { + if ($Clear) + { Write-Debug "[Set-JiraIssueLabel] Clearing all labels" $newLabels = @() } - elseif ($PSCmdlet.ParameterSetName -eq 'ReplaceLabels') { + elseif ($PSCmdlet.ParameterSetName -eq 'ReplaceLabels') + { Write-Debug "[Set-JiraIssueLabel] Set parameter was used; existing labels will be overwritten" $newLabels = $Set } - elseif ($currentLabels -eq $null -or $currentLabels.Count -eq 0) { + elseif ($currentLabels -eq $null -or $currentLabels.Count -eq 0) + { Write-Debug "[Set-JiraIssueLabel] Issue currently has no labels" - if ($Add) { + if ($Add) + { Write-Debug "[Set-JiraIssueLabel] Setting labels to Add parameter" $newLabels = $Add } - else { + else + { Write-Debug "[Set-JiraIssueLabel] No labels were specified to be added; nothing to do" $isDirty = $false } } - else { + else + { Write-Debug "[Set-JiraIssueLabel] Calculating new labels" # If $Add is not provided (null), this can end up with an # extra $null being added to the array, so we need to @@ -116,7 +127,8 @@ $newLabels = $currentLabels + $Add | Where-Object -FilterScript {$_ -ne $null -and $Remove -notcontains $_} } - if ($isDirty) { + if ($isDirty) + { Write-Debug "[Set-JiraIssueLabel] New labels for the issue: [$($newLabels -join ',')]" $props = @{ @@ -137,23 +149,27 @@ # Should return no results $result = Invoke-JiraMethod -Method Put -URI $url -Body $json -Credential $Credential } - else { + else + { Write-Debug "[Set-JiraIssueLabel] No changes are necessary." } - if ($PassThru) { + if ($PassThru) + { Write-Debug "[Set-JiraIssue] PassThru was specified. Obtaining updated reference to issue" Get-JiraIssue -Key $issueObj.Key -Credential $Credential } } - else { + else + { Write-Debug "[Set-JiraIssue] Unable to identify issue [$i]. Writing error message." Write-Error "Unable to identify issue [$i]" } } } - end { + end + { Write-Debug "[Set-JiraIssueLabel] Complete" } } diff --git a/PSJira/Public/Set-JiraUser.ps1 b/PSJira/Public/Set-JiraUser.ps1 index 11c3cc8e..c0a24d31 100644 --- a/PSJira/Public/Set-JiraUser.ps1 +++ b/PSJira/Public/Set-JiraUser.ps1 @@ -29,26 +29,26 @@ function Set-JiraUser param( # Username or user object obtained from Get-JiraUser. [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true)] + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] [Alias('UserName')] [Object[]] $User, # Display name to set. [Parameter(ParameterSetName = 'ByNamedParameters', - Mandatory = $false)] + Mandatory = $false)] [String] $DisplayName, # E-mail address to set. [Parameter(ParameterSetName = 'ByNamedParameters', - Mandatory = $false)] + Mandatory = $false)] [String] $EmailAddress, # Hashtable (dictionary) of additional information to set. [Parameter(ParameterSetName = 'ByHashtable', - Mandatory = $true, - Position = 1)] + Mandatory = $true, + Position = 1)] [Hashtable] $Property, # Credentials to use to connect to JIRA. @@ -75,7 +75,9 @@ function Set-JiraUser { Write-Debug "[Set-JiraIssue] Nothing to do." return - } else { + } + else + { Write-Debug "[Set-JiraIssue] Building property hashtable" if ($DisplayName) { @@ -87,7 +89,9 @@ function Set-JiraUser $updateProps.emailAddress = $EmailAddress } } - } else { + } + else + { $updateProps = $Property } @@ -117,10 +121,14 @@ function Set-JiraUser Write-Debug "[Set-JiraUser] PassThru flag was specified. Invoking Get-JiraUser to get an updated reference to user [$u]" Write-Output (Get-JiraUser -InputObject $u) } - } else { + } + else + { Write-Debug "[Set-JiraUser] JIRA returned no results to display." } - } else { + } + else + { Write-Debug "[Set-JiraUser] Unable to identify user [$u]. Writing error message." Write-Error "Unable to identify user [$u]" } @@ -132,5 +140,3 @@ function Set-JiraUser Write-Debug "[Set-JiraUser] Complete" } } - - diff --git a/Tests/PSJira.Help.Tests.ps1 b/Tests/PSJira.Help.Tests.ps1 index bcfeb882..6d12d108 100644 --- a/Tests/PSJira.Help.Tests.ps1 +++ b/Tests/PSJira.Help.Tests.ps1 @@ -1,4 +1,4 @@ -<# +<# .NOTES =========================================================================== Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.119 @@ -34,16 +34,16 @@ Enter a CommandInfo object, such as the object that Get-Command returns. You can also pipe a CommandInfo object to the function. This parameter takes a CommandInfo object, instead of a command name, so -you can use the parameters of Get-Command to specify the module and version +you can use the parameters of Get-Command to specify the module and version of the command. .EXAMPLE PS C:\> Get-ParametersDefaultFirst -Command (Get-Command New-Guid) -This command uses the Command parameter to specify the command to +This command uses the Command parameter to specify the command to Get-ParametersDefaultFirst .EXAMPLE -PS C:\> Get-Command New-Guid | Get-ParametersDefaultFirst +PS C:\> Get-Command New-Guid | Get-ParametersDefaultFirst You can also pipe a CommandInfo object to Get-ParametersDefaultFirst .EXAMPLE @@ -54,7 +54,7 @@ command runs Get-Command module-qualified name value. .EXAMPLE PS C:\> $ModuleSpec = @{ModuleName='BetterCredentials';RequiredVersion=4.3} PS C:\> Get-Command -FullyQualifiedName $ModuleSpec | Get-ParametersDefaultFirst -This command uses a Microsoft.PowerShell.Commands.ModuleSpecification object to +This command uses a Microsoft.PowerShell.Commands.ModuleSpecification object to specify the module and version. You can also use it to specify the module GUID. Then, it pipes the CommandInfo object to Get-ParametersDefaultFirst. #> @@ -67,7 +67,7 @@ function Get-ParametersDefaultFirst [System.Management.Automation.CommandInfo] $Command ) - + BEGIN { $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' @@ -79,7 +79,7 @@ function Get-ParametersDefaultFirst { $defaultParameters = ($Command.ParameterSets | Where-Object Name -eq $defaultPSetName).parameters | Where-Object Name -NotIn $common $otherParameters = ($Command.ParameterSets | Where-Object Name -ne $defaultPSetName).parameters | Where-Object Name -NotIn $common - + $parameters += $defaultParameters if ($parameters -and $otherParameters) { @@ -96,8 +96,8 @@ function Get-ParametersDefaultFirst { $parameters = $Command.ParameterSets.Parameters | Where-Object Name -NotIn $common | Sort-Object Name -Unique } - - + + return $parameters } END { } @@ -143,70 +143,70 @@ $commands = Get-Command -Module $module -CommandType Cmdlet, Function, Workflow foreach ($command in $commands) { $commandName = $command.Name - + # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets $Help = Get-Help $commandName -ErrorAction SilentlyContinue - + Describe "Test help for $commandName" -Tag "CommandHelp" { - + # If help is not found, synopsis in auto-generated help is the syntax diagram It "should not be auto-generated" { $Help.Synopsis | Should Not BeLike '*`[``]*' } - + # Should be a synopsis for every function It "gets synopsis for $commandName" { $Help.Synopsis | Should Not beNullOrEmpty } - + # Should be a description for every function It "gets description for $commandName" { $Help.Description | Should Not BeNullOrEmpty } - + # Should be at least one example It "gets example code from $commandName" { ($Help.Examples.Example | Select-Object -First 1).Code | Should Not BeNullOrEmpty } - + # Should be at least one example description It "gets example help from $commandName" { ($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should Not BeNullOrEmpty } - + It "has at least as many examples as ParameterSets" { - ($Help.Examples.Example | Measure-Object).Count | Should Not BeLessThan $command.ParameterSets.Count + ($Help.Examples.Example | Measure-Object).Count | Should Not BeLessThan $command.ParameterSets.Count } - + Context "Test parameter help for $commandName" { - + $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' - - # Get parameters. When >1 parameter with same name, + + # Get parameters. When >1 parameter with same name, # get parameter from the default parameter set, if any. $parameters = Get-ParametersDefaultFirst -Command $command - + $parameterNames = $parameters.Name $HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique - + foreach ($parameter in $parameters) { $parameterName = $parameter.Name $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName - + # Should be a description for every parameter If ($parameterName -notmatch 'Confirm|WhatIf') { It "gets help for parameter: $parameterName : in $commandName" { $parameterHelp.Description.Text | Should Not BeNullOrEmpty } } - + # Required value in Help should match IsMandatory property of parameter It "help for $parameterName parameter in $commandName has correct Mandatory value" { $codeMandatory = $parameter.IsMandatory.toString() $parameterHelp.Required | Should Be $codeMandatory } - + # Parameter type in Help should match code It "help for $commandName has correct parameter type for $parameterName" { $codeType = $parameter.ParameterType.Name @@ -215,7 +215,7 @@ foreach ($command in $commands) $helpType | Should be $codeType } } - + foreach ($helpParm in $HelpParameterNames) { # Shouldn't find extra parameters in help. It "finds help parameter in code: $helpParm" { From 67e3f20544971000c976e95d52e02bdeb445a7af Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 10:22:22 -0500 Subject: [PATCH 042/102] Updated VSCode settings and CI pipeline As it turns out, there are quite a few cool new features in VSCode and the PowerShell extension. These changes provide better integration with that editor and an improved CI pipeline and framework. tasks.json has updated the task engien version from 0.1.0 to 2.0.0, allowing VS Code to use the new integrated terminal for tasks instead of the output window. A new build script (taken from a Plaster example template) provides much greater flexibility in the build process. In theory, we can now build the module locally as well as in AppVeyor (though the environment may still be slightly different). By implementing the BuildHelpers module by RamblingCookieMonster, we also gain the ability to fill out the FunctionsToExport key in the module manifest automatically on build. This means that the file in the repo no longer needs to be updated for each function, and the version in the gallery takes advantage of the improved load times by specifying each function. This is still a bit experimental, since I want to see how AppVeyor handles it, but locally everything is working great. --- .gitignore | 3 + .vscode/launch.json | 37 ++ .vscode/settings.json | 4 + .vscode/tasks.cmd | 9 - .vscode/tasks.json | 140 ++++++-- PSJira/PSJira.psd1 | 11 +- ScriptAnalyzerSettings.psd1 | 34 ++ Tests/PSJira.Tests.ps1 | 55 +-- Tools/Appveyor.ps1 | 27 +- Tools/psake.ps1 | 2 + build/build.ps1 | 6 + build/build.psake.ps1 | 699 ++++++++++++++++++++++++++++++++++++ build/build.settings.ps1 | 290 +++++++++++++++ 13 files changed, 1245 insertions(+), 72 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json delete mode 100644 .vscode/tasks.cmd create mode 100644 ScriptAnalyzerSettings.psd1 create mode 100644 build/build.ps1 create mode 100644 build/build.psake.ps1 create mode 100644 build/build.settings.ps1 diff --git a/.gitignore b/.gitignore index 0b9d9dca..7ec1da86 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ config.xml docs/_build/* docs/_build.html/* +# Ignore Release directory generated by local builds +Release/* + ####### # Excerpts from https://www.gitignore.io ####### diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..a29bcafe --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,37 @@ +{ + "version": "0.2.0", + "configurations": [ + + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File", + "script": "${file}", + "args": [], + "cwd": "${file}" + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File w/Args Prompt", + "script": "${file}", + "args": [ + "${command:SpecifyScriptArgs}" + ], + "cwd": "${file}" + }, + { + "type": "PowerShell", + "request": "attach", + "name": "PowerShell Attach to Host Process", + "processId": "${command:PickPSHostProcess}", + "runspaceId": 1 + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Interactive Session", + "cwd": "${workspaceRoot}" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..128e7ec0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.trimTrailingWhitespace": true +} \ No newline at end of file diff --git a/.vscode/tasks.cmd b/.vscode/tasks.cmd deleted file mode 100644 index 6bbe21f1..00000000 --- a/.vscode/tasks.cmd +++ /dev/null @@ -1,9 +0,0 @@ -@rem Do not edit! This file is generated by New-VSCodeTask.ps1 -@echo off -if "%1" == "!" goto start -chcp 65001 > nul -PowerShell.exe -NoProfile -ExecutionPolicy Bypass "& 'D:\Documents\Projects\PSJira\Build\Invoke-Build.ps1' -File 'D:\Documents\Projects\PSJira\Build\PSJira.build.ps1' %1" -exit -:start -shift -start PowerShell.exe -NoExit -NoProfile -ExecutionPolicy Bypass "& 'D:\Documents\Projects\PSJira\Build\Invoke-Build.ps1' -File 'D:\Documents\Projects\PSJira\Build\PSJira.build.ps1' %1" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ca907248..4efcbc3e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,29 +1,121 @@ -// Do not edit! This file is generated by New-VSCodeTask.ps1 -// Modify the build script instead and regenerate this file. +// Available variables which can be used inside of strings. +// ${workspaceRoot}: the root folder of the team +// ${file}: the current opened file +// ${relativeFile}: the current opened file relative to workspaceRoot +// ${fileBasename}: the current opened file's basename +// ${fileDirname}: the current opened file's dirname +// ${fileExtname}: the current opened file's extension +// ${cwd}: the current working directory of the spawned process { - "version": "0.1.0", - "command": ".\\.vscode\\tasks.cmd", - "suppressTaskName": false, - "showOutput": "always", - "tasks": [ - { - "isBuildCommand": true, - "taskName": "." + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + + // Start PowerShell + "windows": { + "command": "${env.windir}\\system32\\windowspowershell\\v1.0\\PowerShell.exe" }, - { - "taskName": "Init" + "linux": { + "command": "/usr/bin/powershell" }, - { - "taskName": "Test" + "osx": { + "command": "/usr/local/bin/powershell" }, - { - "taskName": "Build" - }, - { - "taskName": "Deploy" - }, - { - "taskName": "?" - } - ] + + // The command is a shell script + "isShellCommand": true, + + // Show the output window always + "showOutput": "always", + + "args": [ + "-NoProfile", "-ExecutionPolicy", "Bypass" + ], + + // Associate with test task runner + "tasks": [ + { + "taskName": "Clean", + "suppressTaskName": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking psake on build.psake.ps1 -taskList Clean'; Invoke-psake build\\build.psake.ps1 -taskList Clean;", + "Invoke-Command { Write-Host 'Completed Clean task in task runner.' }" + ] + }, + { + "taskName": "Build", + "suppressTaskName": true, + "isBuildCommand": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking psake on build.psake.ps1 -taskList Build'; Invoke-psake build\\build.psake.ps1 -taskList Build;", + "Invoke-Command { Write-Host 'Completed Build task in task runner.' }" + ] + }, + { + "taskName": "BuildHelp", + "suppressTaskName": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking psake on build.psake.ps1 -taskList BuildHelp'; Invoke-psake build\\build.psake.ps1 -taskList BuildHelp;", + "Invoke-Command { Write-Host 'Completed BuildHelp task in task runner.' }" + ] + }, + { + "taskName": "Analyze", + "suppressTaskName": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking psake on build.psake.ps1 -taskList Analyze'; Invoke-psake build\\build.psake.ps1 -taskList Analyze;", + "Invoke-Command { Write-Host 'Completed Analyze task in task runner.' }" + ] + }, + { + "taskName": "Install", + "suppressTaskName": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking psake on build.psake.ps1 -taskList Install'; Invoke-psake build\\build.psake.ps1 -taskList Install;", + "Invoke-Command { Write-Host 'Completed Install task in task runner.' }" + ] + }, + { + "taskName": "Publish", + "suppressTaskName": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking psake on build.psake.ps1 -taskList Publish'; Invoke-psake build\\build.psake.ps1 -taskList Publish;", + "Invoke-Command { Write-Host 'Completed Publish task in task runner.' }" + ] + }, + { + "taskName": "Test", + "suppressTaskName": true, + "isTestCommand": true, + "showOutput": "always", + "args": [ + "Write-Host 'Invoking Pester'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};", + "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" + ], + "problemMatcher": [ + { + "owner": "powershell", + "fileLocation": ["absolute"], + "severity": "error", + "pattern": [ + { + "regexp": "^\\s*(\\[-\\]\\s*.*?)(\\d+)ms\\s*$", + "message": 1 + }, + { + "regexp": "^\\s+at\\s+[^,]+,\\s*(.*?):\\s+line\\s+(\\d+)$", + "file": 1, + "line": 2 + } + ] + } + ] + } + ] } diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index b38925cd..e910d376 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -69,16 +69,7 @@ FormatsToProcess = 'PSJira.format.ps1xml' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Get-JiraComponent', 'Format-Jira', - 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', - 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', - 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', - 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', 'Get-JiraRemoteLink', - 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', - 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', - 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraRemoteLink', - 'Remove-JiraSession', 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', - 'Set-JiraIssueLabel', 'Set-JiraUser' +FunctionsToExport = '*' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() diff --git a/ScriptAnalyzerSettings.psd1 b/ScriptAnalyzerSettings.psd1 new file mode 100644 index 00000000..b4dd6ca4 --- /dev/null +++ b/ScriptAnalyzerSettings.psd1 @@ -0,0 +1,34 @@ +@{ + # Use Severity when you want to limit the generated diagnostic records to a + # subset of: Error, Warning and Information. + # Uncomment the following line if you only want Errors and Warnings but + # not Information diagnostic records. + #Severity = @('Error','Warning') + + # Use IncludeRules when you want to run only a subset of the default rule set. + #IncludeRules = @('PSAvoidDefaultValueSwitchParameter', + # 'PSMisleadingBacktick', + # 'PSMissingModuleManifestField', + # 'PSReservedCmdletChar', + # 'PSReservedParams', + # 'PSShouldProcess', + # 'PSUseApprovedVerbs', + # 'PSUseDeclaredVarsMoreThanAssigments') + + # Use ExcludeRules when you want to run most of the default set of rules except + # for a few rules you wish to "exclude". Note: if a rule is in both IncludeRules + # and ExcludeRules, the rule will be excluded. + #ExcludeRules = @('PSAvoidUsingWriteHost') + + # You can use the following entry to supply parameters to rules that take parameters. + # For instance, the PSAvoidUsingCmdletAliases rule takes a whitelist for aliases you + # want to allow. + #Rules = @{ + # Do not flag 'cd' alias. + # PSAvoidUsingCmdletAliases = @{Whitelist = @('cd')} + + # Check if your script uses cmdlets that are compatible on PowerShell Core, + # version 6.0.0-alpha, on Linux. + # PSUseCompatibleCmdlets = @{Compatibility = @("core-6.0.0-alpha-linux")} + #} +} diff --git a/Tests/PSJira.Tests.ps1 b/Tests/PSJira.Tests.ps1 index daa1e4ab..efa5f0cd 100644 --- a/Tests/PSJira.Tests.ps1 +++ b/Tests/PSJira.Tests.ps1 @@ -105,30 +105,37 @@ Describe "PSJira" { } } - Context "Function checking" { - $functionFiles = Get-ChildItem $publicFunctions -Filter *.ps1 | - Select-Object -ExpandProperty BaseName | - Where-Object { $_ -notlike "*.Tests" } - - $internalFiles = Get-ChildItem $internalFunctions -Filter *.ps1 | - Select-Object -ExpandProperty BaseName | - Where-Object { $_ -notlike "*.Tests" } - - #$exportedFunctions = $script:manifest.ExportedFunctions.Values.Name - $exportedFunctions = $script:manifest.FunctionsToExport - - foreach ($f in $functionFiles) { - It "Exports $f" { - $exportedFunctions -contains $f | Should Be $true - } - } - - foreach ($f in $internalFiles) { - It "Does not export $f" { - $exportedFunctions -contains $f | Should Be $false - } - } - } + # The CI changes I'm testng now will render this section obsolete, + # as it should automatically patch the module manifest file with all + # exported function names. + # Leaving the code here for the moment while I can ensure those + # features are working correctly. + + # + # Context "Function checking" { + # $functionFiles = Get-ChildItem $publicFunctions -Filter *.ps1 | + # Select-Object -ExpandProperty BaseName | + # Where-Object { $_ -notlike "*.Tests" } + + # $internalFiles = Get-ChildItem $internalFunctions -Filter *.ps1 | + # Select-Object -ExpandProperty BaseName | + # Where-Object { $_ -notlike "*.Tests" } + + # #$exportedFunctions = $script:manifest.ExportedFunctions.Values.Name + # $exportedFunctions = $script:manifest.FunctionsToExport + + # foreach ($f in $functionFiles) { + # It "Exports $f" { + # $exportedFunctions -contains $f | Should Be $true + # } + # } + + # foreach ($f in $internalFiles) { + # It "Does not export $f" { + # $exportedFunctions -contains $f | Should Be $false + # } + # } + # } Context "Style checking" { diff --git a/Tools/Appveyor.ps1 b/Tools/Appveyor.ps1 index 6756542c..e317dc61 100644 --- a/Tools/Appveyor.ps1 +++ b/Tools/Appveyor.ps1 @@ -54,12 +54,29 @@ Write-Host "AppVeyor build initialized (Job ID $JobId)" -ForegroundColor Cyan Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null # Don't forget -Force! -Install-Module Pester,psake -Force -Write-Host "Attempting to run $env:APPVEYOR_BUILD_FOLDER\Tools\psake.ps1" -ForegroundColor Cyan -Invoke-psake $env:APPVEYOR_BUILD_FOLDER\Tools\psake.ps1 +Install-Module Pester,psake,BuildHelpers -Force + +# Init the BuildHelpers environment variables +Set-BuildEnvironment + +Write-Host "BuildHelpers environment details:`n$(Get-Item env:BH* | Out-String)`n" -ForegroundColor Cyan + +Write-Host "Running tests" -ForegroundColor Cyan +Invoke-psake $env:APPVEYOR_BUILD_FOLDER\build\build.psake.ps1 -taskList Test + +if (-not $psake.build_success) { + Write-Error "Build failed." + exit 1 +} + +if ($env:APPVEYOR_REPO_BRANCH -ne 'master' -or $env:APPVEYOR_PULL_REQUEST_NUMBER) { + Write-Host "This commit is not to the master branch. It will not be published." -ForegroundColor Yellow + exit 0 +} + +Write-Host "Running publish task" +Invoke-psake $env:APPVEYOR_BUILD_FOLDER\build\build.psake.ps1 -taskList Publish Write-Host Write-Host "=== Completed AppVeyor.ps1 ===" -ForegroundColor Green Write-Host - -exit ( [int] (-not $psake.build_success) ) \ No newline at end of file diff --git a/Tools/psake.ps1 b/Tools/psake.ps1 index b88b7834..60f41dae 100644 --- a/Tools/psake.ps1 +++ b/Tools/psake.ps1 @@ -1,3 +1,5 @@ +# No longer used as of 2017-05-22. See build\build.psake.ps1 instead. + # PSake makes variables declared here available in other scriptblocks Properties { # This refers to the root of the project directory diff --git a/build/build.ps1 b/build/build.ps1 new file mode 100644 index 00000000..5fe2b11a --- /dev/null +++ b/build/build.ps1 @@ -0,0 +1,6 @@ +#Requires -Modules psake,BuildHelpers + +# This is a shortcut script that just invokes the "main" build logic. + +# Builds the module by invoking psake on the build.psake.ps1 script. +Invoke-PSake $PSScriptRoot\build.psake.ps1 -taskList Build diff --git a/build/build.psake.ps1 b/build/build.psake.ps1 new file mode 100644 index 00000000..f1c467c7 --- /dev/null +++ b/build/build.psake.ps1 @@ -0,0 +1,699 @@ +#Requires -Modules psake,BuildHelpers + +############################################################################## +# DO NOT MODIFY THIS FILE! Modify build.settings.ps1 instead. +############################################################################## + +############################################################################## +# This is the PowerShell Module psake build script. It defines the following tasks: +# +# Clean, Build, Sign, BuildHelp, Install, Test and Publish. +# +# The default task is Build. This task copies the appropriate files from the +# $SrcRootDir under the $OutDir. Later, other tasks such as Sign and BuildHelp +# will further modify the contents of $OutDir and add new files. +# +# The Sign task will only sign scripts if the $SignScripts variable is set to +# $true. A code-signing certificate is required for this task to complete. +# +# The BuildHelp task invokes platyPS to generate markdown files from +# comment-based help for your exported commands. platyPS then generates +# a help file for your module from the markdown files. +# +# The Install task simplies copies the module folder under $OutDir to your +# profile's Modules folder. +# +# The Test task invokes Pester on the $TestRootDir. +# +# The Publish task uses the Publish-Module command to publish +# to either the PowerShell Gallery (the default) or you can change +# the $PublishRepository property to the name of an alternate repository. +# Note: the Publish task requires that the Test task execute without failures. +# +# You can exeute a specific task, such as the Test task by running the +# following command: +# +# PS C:\> invoke-psake build.psake.ps1 -taskList Test +# +# You can execute the Publish task with the following command. +# The first time you execute the Publish task, you will be prompted to enter +# your PowerShell Gallery NuGetApiKey. After entering the key, it is encrypted +# and stored so you will not have to enter it again. +# +# PS C:\> invoke-psake build.psake.ps1 -taskList Publish +# +# You can verify the stored and encrypted NuGetApiKey by running the following +# command which will display a portion of your NuGetApiKey in plain text. +# +# PS C:\> invoke-psake build.psake.ps1 -taskList ShowApiKey +# +# You can store a new NuGetApiKey with this command. You can leave off +# the -properties parameter and you'll be prompted for the key. +# +# PS C:\> invoke-psake build.psake.ps1 -taskList StoreApiKey -properties @{NuGetApiKey='test123'} +# + +############################################################################### +# Dot source the user's customized properties and extension tasks. +############################################################################### +. $PSScriptRoot\build.settings.ps1 + +############################################################################### +# Private properties. +############################################################################### +Properties { + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $ModuleOutDir = "$OutDir\$ModuleName" + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $UpdatableHelpOutDir = "$OutDir\UpdatableHelp" + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $SharedProperties = @{} + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $LineSep = "-" * 78 +} + +############################################################################### +# Core task implementations. Avoid modifying these tasks. +############################################################################### +Task default -depends Build + +Task Init -requiredVariables OutDir,ProjectRoot { + if (!(Test-Path -LiteralPath $OutDir)) { + New-Item $OutDir -ItemType Directory -Verbose:$VerbosePreference > $null + } + else { + Write-Verbose "$($psake.context.currentTaskName) - directory already exists '$OutDir'." + } + + Set-BuildEnvironment -Path $ProjectRoot + Set-Location $ProjectRoot +} + +Task Clean -depends Init -requiredVariables OutDir { + # Maybe a bit paranoid but this task nuked \ on my laptop. Good thing I was not running as admin. + if ($OutDir.Length -gt 3) { + Get-ChildItem $OutDir | Remove-Item -Recurse -Force -Verbose:$VerbosePreference + } + else { + Write-Verbose "$($psake.context.currentTaskName) - `$OutDir '$OutDir' must be longer than 3 characters." + } +} + +Task StageFiles -depends Init, Clean, BeforeStageFiles, CoreStageFiles, AfterStageFiles { +} + +Task CoreStageFiles -requiredVariables ModuleOutDir, SrcRootDir { + if (!(Test-Path -LiteralPath $ModuleOutDir)) { + New-Item $ModuleOutDir -ItemType Directory -Verbose:$VerbosePreference > $null + } + else { + Write-Verbose "$($psake.context.currentTaskName) - directory already exists '$ModuleOutDir'." + } + + Copy-Item -Path $SrcRootDir\* -Destination $ModuleOutDir -Recurse -Exclude $Exclude -Verbose:$VerbosePreference +} + +Task Build -depends Init, Clean, BeforeBuild, StageFiles, Analyze, Sign, AfterBuild { +} + +Task Analyze -depends StageFiles ` + -requiredVariables ModuleOutDir, ScriptAnalysisEnabled, ScriptAnalysisFailBuildOnSeverityLevel, ScriptAnalyzerSettingsPath { + if (!$ScriptAnalysisEnabled) { + "Script analysis is not enabled. Skipping $($psake.context.currentTaskName) task." + return + } + + if (!(Get-Module PSScriptAnalyzer -ListAvailable)) { + "PSScriptAnalyzer module is not installed. Skipping $($psake.context.currentTaskName) task." + return + } + + "ScriptAnalysisFailBuildOnSeverityLevel set to: $ScriptAnalysisFailBuildOnSeverityLevel" + + $analysisResult = Invoke-ScriptAnalyzer -Path $ModuleOutDir -Settings $ScriptAnalyzerSettingsPath -Recurse -Verbose:$VerbosePreference + $analysisResult | Format-Table + switch ($ScriptAnalysisFailBuildOnSeverityLevel) { + 'None' { + return + } + 'Error' { + Assert -conditionToCheck ( + ($analysisResult | Where-Object Severity -eq 'Error').Count -eq 0 + ) -failureMessage 'One or more ScriptAnalyzer errors were found. Build cannot continue!' + } + 'Warning' { + Assert -conditionToCheck ( + ($analysisResult | Where-Object { + $_.Severity -eq 'Warning' -or $_.Severity -eq 'Error' + }).Count -eq 0) -failureMessage 'One or more ScriptAnalyzer warnings were found. Build cannot continue!' + } + default { + Assert -conditionToCheck ( + $analysisResult.Count -eq 0 + ) -failureMessage 'One or more ScriptAnalyzer issues were found. Build cannot continue!' + } + } +} + +Task Sign -depends StageFiles -requiredVariables CertPath, SettingsPath, ScriptSigningEnabled { + if (!$ScriptSigningEnabled) { + "Script signing is not enabled. Skipping $($psake.context.currentTaskName) task." + return + } + + $validCodeSigningCerts = Get-ChildItem -Path $CertPath -CodeSigningCert -Recurse | Where-Object NotAfter -ge (Get-Date) + if (!$validCodeSigningCerts) { + throw "There are no non-expired code-signing certificates in $CertPath. You can either install " + + "a code-signing certificate into the certificate store or disable script analysis in build.settings.ps1." + } + + $certSubjectNameKey = "CertSubjectName" + $storeCertSubjectName = $true + + # Get the subject name of the code-signing certificate to be used for script signing. + if (!$CertSubjectName -and ($CertSubjectName = GetSetting -Key $certSubjectNameKey -Path $SettingsPath)) { + $storeCertSubjectName = $false + } + elseif (!$CertSubjectName) { + "A code-signing certificate has not been specified." + "The following non-expired, code-signing certificates are available in your certificate store:" + $validCodeSigningCerts | Format-List Subject,Issuer,Thumbprint,NotBefore,NotAfter + + $CertSubjectName = Read-Host -Prompt 'Enter the subject name (case-sensitive) of the certificate to use for script signing' + } + + # Find a code-signing certificate that matches the specified subject name. + $certificate = $validCodeSigningCerts | + Where-Object { $_.SubjectName.Name -cmatch [regex]::Escape($CertSubjectName) } | + Sort-Object NotAfter -Descending | Select-Object -First 1 + + if ($certificate) { + $SharedProperties.CodeSigningCertificate = $certificate + + if ($storeCertSubjectName) { + SetSetting -Key $certSubjectNameKey -Value $certificate.SubjectName.Name -Path $SettingsPath + "The new certificate subject name has been stored in ${SettingsPath}." + } + else { + "Using stored certificate subject name $CertSubjectName from ${SettingsPath}." + } + + $LineSep + "Using code-signing certificate: $certificate" + $LineSep + + $files = @(Get-ChildItem -Path $ModuleOutDir\* -Recurse -Include *.ps1,*.psm1) + foreach ($file in $files) { + $setAuthSigParams = @{ + FilePath = $file.FullName + Certificate = $certificate + Verbose = $VerbosePreference + } + + $result = Microsoft.PowerShell.Security\Set-AuthenticodeSignature @setAuthSigParams + if ($result.Status -ne 'Valid') { + throw "Failed to sign script: $($file.FullName)." + } + + "Successfully signed script: $($file.Name)" + } + } + else { + $expiredCert = Get-ChildItem -Path $CertPath -CodeSigningCert -Recurse | + Where-Object { ($_.SubjectName.Name -cmatch [regex]::Escape($CertSubjectName)) -and + ($_.NotAfter -lt (Get-Date)) } + Sort-Object NotAfter -Descending | Select-Object -First 1 + + if ($expiredCert) { + throw "The code-signing certificate `"$($expiredCert.SubjectName.Name)`" EXPIRED on $($expiredCert.NotAfter)." + } + + throw 'No valid certificate subject name supplied or stored.' + } +} + +Task BuildHelp -depends Build, BeforeBuildHelp, GenerateMarkdown, GenerateHelpFiles, AfterBuildHelp { +} + +Task GenerateMarkdown -requiredVariables DefaultLocale, DocsRootDir, ModuleName, ModuleOutDir { + if (!(Get-Module platyPS -ListAvailable)) { + "platyPS module is not installed. Skipping $($psake.context.currentTaskName) task." + return + } + + $moduleInfo = Import-Module $ModuleOutDir\$ModuleName.psd1 -Global -Force -PassThru + + try { + if ($moduleInfo.ExportedCommands.Count -eq 0) { + "No commands have been exported. Skipping $($psake.context.currentTaskName) task." + return + } + + if (!(Test-Path -LiteralPath $DocsRootDir)) { + New-Item $DocsRootDir -ItemType Directory > $null + } + + if (Get-ChildItem -LiteralPath $DocsRootDir -Filter *.md -Recurse) { + Get-ChildItem -LiteralPath $DocsRootDir -Directory | ForEach-Object { + Update-MarkdownHelp -Path $_.FullName -Verbose:$VerbosePreference > $null + } + } + + # ErrorAction set to SilentlyContinue so this command will not overwrite an existing MD file. + New-MarkdownHelp -Module $ModuleName -Locale $DefaultLocale -OutputFolder $DocsRootDir\$DefaultLocale ` + -WithModulePage -ErrorAction SilentlyContinue -Verbose:$VerbosePreference > $null + } + finally { + Remove-Module $ModuleName + } +} + +Task GenerateHelpFiles -requiredVariables DocsRootDir, ModuleName, ModuleOutDir, OutDir { + if (!(Get-Module platyPS -ListAvailable)) { + "platyPS module is not installed. Skipping $($psake.context.currentTaskName) task." + return + } + + if (!(Get-ChildItem -LiteralPath $DocsRootDir -Filter *.md -Recurse -ErrorAction SilentlyContinue)) { + "No markdown help files to process. Skipping $($psake.context.currentTaskName) task." + return + } + + $helpLocales = (Get-ChildItem -Path $DocsRootDir -Directory).Name + + # Generate the module's primary MAML help file. + foreach ($locale in $helpLocales) { + New-ExternalHelp -Path $DocsRootDir\$locale -OutputPath $ModuleOutDir\$locale -Force ` + -ErrorAction SilentlyContinue -Verbose:$VerbosePreference > $null + } +} + +Task BuildUpdatableHelp -depends BuildHelp, BeforeBuildUpdatableHelp, CoreBuildUpdatableHelp, AfterBuildUpdatableHelp { +} + +Task CoreBuildUpdatableHelp -requiredVariables DocsRootDir, ModuleName, UpdatableHelpOutDir { + if (!(Get-Module platyPS -ListAvailable)) { + "platyPS module is not installed. Skipping $($psake.context.currentTaskName) task." + return + } + + $helpLocales = (Get-ChildItem -Path $DocsRootDir -Directory).Name + + # Create updatable help output directory. + if (!(Test-Path -LiteralPath $UpdatableHelpOutDir)) { + New-Item $UpdatableHelpOutDir -ItemType Directory -Verbose:$VerbosePreference > $null + } + else { + Write-Verbose "$($psake.context.currentTaskName) - directory already exists '$UpdatableHelpOutDir'." + Get-ChildItem $UpdatableHelpOutDir | Remove-Item -Recurse -Force -Verbose:$VerbosePreference + } + + # Generate updatable help files. Note: this will currently update the version number in the module's MD + # file in the metadata. + foreach ($locale in $helpLocales) { + New-ExternalHelpCab -CabFilesFolder $ModuleOutDir\$locale -LandingPagePath $DocsRootDir\$locale\$ModuleName.md ` + -OutputFolder $UpdatableHelpOutDir -Verbose:$VerbosePreference > $null + } +} + +Task GenerateFileCatalog -depends Build, BuildHelp, BeforeGenerateFileCatalog, CoreGenerateFileCatalog, AfterGenerateFileCatalog { +} + +Task CoreGenerateFileCatalog -requiredVariables CatalogGenerationEnabled, CatalogVersion, ModuleName, ModuleOutDir, OutDir { + if (!$CatalogGenerationEnabled) { + "FileCatalog generation is not enabled. Skipping $($psake.context.currentTaskName) task." + return + } + + if (!(Get-Command Microsoft.PowerShell.Security\New-FileCatalog -ErrorAction SilentlyContinue)) { + "FileCatalog commands not available on this version of PowerShell. Skipping $($psake.context.currentTaskName) task." + return + } + + $catalogFilePath = "$OutDir\$ModuleName.cat" + + $newFileCatalogParams = @{ + Path = $ModuleOutDir + CatalogFilePath = $catalogFilePath + CatalogVersion = $CatalogVersion + Verbose = $VerbosePreference + } + + Microsoft.PowerShell.Security\New-FileCatalog @newFileCatalogParams > $null + + if ($ScriptSigningEnabled) { + if ($SharedProperties.CodeSigningCertificate) { + $setAuthSigParams = @{ + FilePath = $catalogFilePath + Certificate = $SharedProperties.CodeSigningCertificate + Verbose = $VerbosePreference + } + + $result = Microsoft.PowerShell.Security\Set-AuthenticodeSignature @setAuthSigParams + if ($result.Status -ne 'Valid') { + throw "Failed to sign file catalog: $($catalogFilePath)." + } + + "Successfully signed file catalog: $($catalogFilePath)" + } + else { + "No code-signing certificate was found to sign the file catalog." + } + } + else { + "Script signing is not enabled. Skipping signing of file catalog." + } + + Move-Item -LiteralPath $newFileCatalogParams.CatalogFilePath -Destination $ModuleOutDir +} + +Task Install -depends Build, BuildHelp, GenerateFileCatalog, BeforeInstall, CoreInstall, AfterInstall { +} + +Task CoreInstall -requiredVariables ModuleOutDir { + if (!(Test-Path -LiteralPath $InstallPath)) { + Write-Verbose 'Creating install directory' + New-Item -Path $InstallPath -ItemType Directory -Verbose:$VerbosePreference > $null + } + + Copy-Item -Path $ModuleOutDir\* -Destination $InstallPath -Verbose:$VerbosePreference -Recurse -Force + "Module installed into $InstallPath" +} + +Task Test -depends Build, BeforeTest, CoreTest, AfterTest { +} + +Task CoreTest -depends Build -requiredVariables TestRootDir, ModuleName, CodeCoverageEnabled, CodeCoverageFiles { + if (!(Get-Module Pester -ListAvailable)) { + "Pester module is not installed. Skipping $($psake.context.currentTaskName) task." + return + } + + Import-Module Pester + + try { + Microsoft.PowerShell.Management\Push-Location -LiteralPath $TestRootDir + + if ($TestOutputFile) { + $testing = @{ + OutputFile = $TestOutputFile + OutputFormat = $TestOutputFormat + PassThru = $true + Verbose = $VerbosePreference + } + } + else { + $testing = @{ + PassThru = $true + Verbose = $VerbosePreference + } + } + + # To control the Pester code coverage, a boolean $CodeCoverageEnabled is used. + if ($CodeCoverageEnabled) { + $testing.CodeCoverage = $CodeCoverageFiles + } + + $testResult = Invoke-Pester @testing + + Assert -conditionToCheck ( + $testResult.FailedCount -eq 0 + ) -failureMessage "One or more Pester tests failed, build cannot continue." + + if ($CodeCoverageEnabled) { + $testCoverage = [int]($testResult.CodeCoverage.NumberOfCommandsExecuted / + $testResult.CodeCoverage.NumberOfCommandsAnalyzed * 100) + "Pester code coverage on specified files: ${testCoverage}%" + } + } + finally { + Microsoft.PowerShell.Management\Pop-Location + Remove-Module $ModuleName -ErrorAction SilentlyContinue + } +} + +Task Publish -depends Build, Test, BuildHelp, GenerateFileCatalog, BeforePublish, CorePublish, AfterPublish { +} + +Task CorePublish -requiredVariables SettingsPath, ModuleOutDir { + $publishParams = @{ + Path = $ModuleOutDir + NuGetApiKey = $NuGetApiKey + } + + # Publishing to the PSGallery requires an API key, so get it. + if ($NuGetApiKey) { + "Using script embedded NuGetApiKey" + } + elseif ($NuGetApiKey = GetSetting -Path $SettingsPath -Key NuGetApiKey) { + "Using stored NuGetApiKey" + } + else { + $promptForKeyCredParams = @{ + DestinationPath = $SettingsPath + Message = 'Enter your NuGet API key in the password field' + Key = 'NuGetApiKey' + } + + $cred = PromptUserForCredentialAndStorePassword @promptForKeyCredParams + $NuGetApiKey = $cred.GetNetworkCredential().Password + "The NuGetApiKey has been stored in $SettingsPath" + } + + $publishParams = @{ + Path = $ModuleOutDir + NuGetApiKey = $NuGetApiKey + } + + # If an alternate repository is specified, set the appropriate parameter. + if ($PublishRepository) { + $publishParams['Repository'] = $PublishRepository + } + + # Consider not using -ReleaseNotes parameter when Update-ModuleManifest has been fixed. + if ($ReleaseNotesPath) { + $publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath) + } + + "Calling Publish-Module..." + Publish-Module @publishParams +} + +############################################################################### +# Secondary/utility tasks - typically used to manage stored build settings. +############################################################################### + +Task ? -description 'Lists the available tasks' { + "Available tasks:" + $psake.context.Peek().Tasks.Keys | Sort-Object +} + +Task RemoveApiKey -requiredVariables SettingsPath { + if (GetSetting -Path $SettingsPath -Key NuGetApiKey) { + RemoveSetting -Path $SettingsPath -Key NuGetApiKey + } +} + +Task StoreApiKey -requiredVariables SettingsPath { + $promptForKeyCredParams = @{ + DestinationPath = $SettingsPath + Message = 'Enter your NuGet API key in the password field' + Key = 'NuGetApiKey' + } + + PromptUserForCredentialAndStorePassword @promptForKeyCredParams + "The NuGetApiKey has been stored in $SettingsPath" +} + +Task ShowApiKey -requiredVariables SettingsPath { + $OFS = "" + if ($NuGetApiKey) { + "The embedded (partial) NuGetApiKey is: $($NuGetApiKey[0..7])" + } + elseif ($NuGetApiKey = GetSetting -Path $SettingsPath -Key NuGetApiKey) { + "The stored (partial) NuGetApiKey is: $($NuGetApiKey[0..7])" + } + else { + "The NuGetApiKey has not been provided or stored." + return + } + + "To see the full key, use the task 'ShowFullApiKey'" +} + +Task ShowFullApiKey -requiredVariables SettingsPath { + if ($NuGetApiKey) { + "The embedded NuGetApiKey is: $NuGetApiKey" + } + elseif ($NuGetApiKey = GetSetting -Path $SettingsPath -Key NuGetApiKey) { + "The stored NuGetApiKey is: $NuGetApiKey" + } + else { + "The NuGetApiKey has not been provided or stored." + } +} + +Task RemoveCertSubjectName -requiredVariables SettingsPath { + if (GetSetting -Path $SettingsPath -Key CertSubjectName) { + RemoveSetting -Path $SettingsPath -Key CertSubjectName + } +} + +Task StoreCertSubjectName -requiredVariables SettingsPath { + $certSubjectName = 'CN=' + $certSubjectName += Read-Host -Prompt 'Enter the certificate subject name for script signing. Use exact casing, CN= prefix will be added' + SetSetting -Key CertSubjectName -Value $certSubjectName -Path $SettingsPath + "The new certificate subject name '$certSubjectName' has been stored in ${SettingsPath}." +} + +Task ShowCertSubjectName -requiredVariables SettingsPath { + $CertSubjectName = GetSetting -Path $SettingsPath -Key CertSubjectName + "The stored certificate is: $CertSubjectName" + + $cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert | + Where-Object { $_.Subject -eq $CertSubjectName -and $_.NotAfter -gt (Get-Date) } | + Sort-Object -Property NotAfter -Descending | Select-Object -First 1 + + if ($cert) { + "A valid certificate for the subject $CertSubjectName has been found" + } + else { + 'A valid certificate has not been found' + } +} + +############################################################################### +# Helper functions +############################################################################### + +function PromptUserForCredentialAndStorePassword { + [Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')] + param( + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $DestinationPath, + + [Parameter(Mandatory)] + [string] + $Message, + + [Parameter(Mandatory, ParameterSetName = 'SaveSetting')] + [string] + $Key + ) + + $cred = Get-Credential -Message $Message -UserName "ignored" + if ($DestinationPath) { + SetSetting -Key $Key -Value $cred.Password -Path $DestinationPath + } + + $cred +} + +function AddSetting { + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSShouldProcess', '', Scope='Function')] + param( + [Parameter(Mandatory)] + [string]$Key, + + [Parameter(Mandatory)] + [string]$Path, + + [Parameter(Mandatory)] + [ValidateNotNull()] + [object]$Value + ) + + switch ($type = $Value.GetType().Name) { + 'securestring' { $setting = $Value | ConvertFrom-SecureString } + default { $setting = $Value } + } + + if (Test-Path -LiteralPath $Path) { + $storedSettings = Import-Clixml -Path $Path + $storedSettings.Add($Key, @($type, $setting)) + $storedSettings | Export-Clixml -Path $Path + } + else { + $parentDir = Split-Path -Path $Path -Parent + if (!(Test-Path -LiteralPath $parentDir)) { + New-Item $parentDir -ItemType Directory > $null + } + + @{$Key = @($type, $setting)} | Export-Clixml -Path $Path + } +} + +function GetSetting { + param( + [Parameter(Mandatory)] + [string]$Key, + + [Parameter(Mandatory)] + [string]$Path + ) + + if (Test-Path -LiteralPath $Path) { + $securedSettings = Import-Clixml -Path $Path + if ($securedSettings.$Key) { + switch ($securedSettings.$Key[0]) { + 'securestring' { + $value = $securedSettings.$Key[1] | ConvertTo-SecureString + $cred = New-Object -TypeName PSCredential -ArgumentList 'jpgr', $value + $cred.GetNetworkCredential().Password + } + default { + $securedSettings.$Key[1] + } + } + } + } +} + +function SetSetting { + param( + [Parameter(Mandatory)] + [string]$Key, + + [Parameter(Mandatory)] + [string]$Path, + + [Parameter(Mandatory)] + [ValidateNotNull()] + [object]$Value + ) + + if (GetSetting -Key $Key -Path $Path) { + RemoveSetting -Key $Key -Path $Path + } + + AddSetting -Key $Key -Value $Value -Path $Path +} + +function RemoveSetting { + param( + [Parameter(Mandatory)] + [string]$Key, + + [Parameter(Mandatory)] + [string]$Path + ) + + if (Test-Path -LiteralPath $Path) { + $storedSettings = Import-Clixml -Path $Path + $storedSettings.Remove($Key) + if ($storedSettings.Count -eq 0) { + Remove-Item -Path $Path + } + else { + $storedSettings | Export-Clixml -Path $Path + } + } + else { + Write-Warning "The build setting file '$Path' has not been created yet." + } +} diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 new file mode 100644 index 00000000..35fc6216 --- /dev/null +++ b/build/build.settings.ps1 @@ -0,0 +1,290 @@ +############################################################################### +# Customize these properties and tasks for your module. +############################################################################### + +Properties { + # ----------------------- Basic properties -------------------------------- + + # Root directory for the project + $ProjectRoot = Split-Path $PSScriptRoot -Parent + + # The root directories for the module's docs, src and test. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $DocsRootDir = "$ProjectRoot\docs" + $SrcRootDir = "$ProjectRoot\PSJira" + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $TestRootDir = "$ProjectRoot\test" + + # The name of your module should match the basename of the PSD1 file. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $ModuleName = Get-Item $SrcRootDir/*.psd1 | + Where-Object { $null -ne (Test-ModuleManifest -Path $_ -ErrorAction SilentlyContinue) } | + Select-Object -First 1 | Foreach-Object BaseName + + # The $OutDir is where module files and updatable help files are staged for signing, install and publishing. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $OutDir = "$ProjectRoot\Release" + + # The local installation directory for the install task. Defaults to your home Modules location. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $InstallPath = Join-Path (Split-Path $profile.CurrentUserAllHosts -Parent) ` + "Modules\$ModuleName\$((Test-ModuleManifest -Path $SrcRootDir\$ModuleName.psd1).Version.ToString())" + + # Default Locale used for help generation, defaults to en-US. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $DefaultLocale = 'en-US' + + # Items in the $Exclude array will not be copied to the $OutDir e.g. $Exclude = @('.gitattributes') + # Typically you wouldn't put any file under the src dir unless the file was going to ship with + # the module. However, if there are such files, add their $SrcRootDir relative paths to the exclude list. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $Exclude = @() + + # ------------------ Script analysis properties --------------------------- + + # Enable/disable use of PSScriptAnalyzer to perform script analysis. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $ScriptAnalysisEnabled = $true + + # When PSScriptAnalyzer is enabled, control which severity level will generate a build failure. + # Valid values are Error, Warning, Information and None. "None" will report errors but will not + # cause a build failure. "Error" will fail the build only on diagnostic records that are of + # severity error. "Warning" will fail the build on Warning and Error diagnostic records. + # "Any" will fail the build on any diagnostic record, regardless of severity. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + [ValidateSet('Error', 'Warning', 'Any', 'None')] + $ScriptAnalysisFailBuildOnSeverityLevel = 'Error' + + # Path to the PSScriptAnalyzer settings file. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $ScriptAnalyzerSettingsPath = "$ProjectRoot\ScriptAnalyzerSettings.psd1" + + # ------------------- Script signing properties --------------------------- + + # Set to $true if you want to sign your scripts. You will need to have a code-signing certificate. + # You can specify the certificate's subject name below. If not specified, you will be prompted to + # provide either a subject name or path to a PFX file. After this one time prompt, the value will + # saved for future use and you will no longer be prompted. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $ScriptSigningEnabled = $false + + # Specify the Subject Name of the certificate used to sign your scripts. Leave it as $null and the + # first time you build, you will be prompted to enter your code-signing certificate's Subject Name. + # This variable is used only if $SignScripts is set to $true. + # + # This does require the code-signing certificate to be installed to your certificate store. If you + # have a code-signing certificate in a PFX file, install the certificate to your certificate store + # with the command below. You may be prompted for the certificate's password. + # + # Import-PfxCertificate -FilePath .\myCodeSigingCert.pfx -CertStoreLocation Cert:\CurrentUser\My + # + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $CertSubjectName = $null + + # Certificate store path. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $CertPath = "Cert:\" + + # -------------------- File catalog properties ---------------------------- + + # Enable/disable generation of a catalog (.cat) file for the module. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $CatalogGenerationEnabled = $true + + # Select the hash version to use for the catalog file: 1 for SHA1 (compat with Windows 7 and + # Windows Server 2008 R2), 2 for SHA2 to support only newer Windows versions. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $CatalogVersion = 2 + + # ---------------------- Testing properties ------------------------------- + + # Enable/disable Pester code coverage reporting. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $CodeCoverageEnabled = $true + + # CodeCoverageFiles specifies the files to perform code coverage analysis on. This property + # acts as a direct input to the Pester -CodeCoverage parameter, so will support constructions + # like the ones found here: https://github.com/pester/Pester/wiki/Code-Coverage. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $CodeCoverageFiles = "$SrcRootDir\*.ps1", "$SrcRootDir\*.psm1" + + # -------------------- Publishing properties ------------------------------ + + # Your NuGet API key for the PSGallery. Leave it as $null and the first time you publish, + # you will be prompted to enter your API key. The build will store the key encrypted in the + # settings file, so that on subsequent publishes you will no longer be prompted for the API key. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $NuGetApiKey = $null + + # Name of the repository you wish to publish to. If $null is specified the default repo (PowerShellGallery) is used. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $PublishRepository = $null + + # Path to the release notes file. Set to $null if the release notes reside in the manifest file. + # The contents of this file are used during publishing for the ReleaseNotes parameter. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $ReleaseNotesPath = "$ProjectRoot\ReleaseNotes.md" + + # ----------------------- Misc properties --------------------------------- + + # In addition, PFX certificates are supported in an interactive scenario only, + # as a way to import a certificate into the user personal store for later use. + # This can be provided using the CertPfxPath parameter. PFX passwords will not be stored. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $SettingsPath = "$env:LOCALAPPDATA\Plaster\NewModuleTemplate\SecuredBuildSettings.clixml" + + # Specifies an output file path to send to Invoke-Pester's -OutputFile parameter. + # This is typically used to write out test results so that they can be sent to a CI + # system like AppVeyor. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $TestOutputFile = "$env:TEMP\TestResults_PS$PSVersion`_$TimeStamp.xml" + + # Specifies the test output format to use when the TestOutputFile property is given + # a path. This parameter is passed through to Invoke-Pester's -OutputFormat parameter. + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $TestOutputFormat = "NUnitXml" +} + +############################################################################### +# Customize these tasks for performing operations before and/or after file staging. +############################################################################### + +# Executes before the StageFiles task. +Task BeforeStageFiles -requiredVariables ProjectRoot { + Write-Host "BuildHelpers environment:`n$(Get-Item env:bh* | Out-String)" -ForegroundColor Green +} + +# Executes after the StageFiles task. +Task AfterStageFiles { +} + +############################################################################### +# Customize these tasks for performing operations before and/or after Build. +############################################################################### + +# Executes before the BeforeStageFiles phase of the Build task. +Task BeforeBuild { +} + +# Executes after the Build task. +Task AfterBuild -requiredVariables ProjectRoot,OutDir { + $outputManifestFile = Join-Path -Path $OutDir -ChildPath 'PSJira\PSJira.psd1' + Write-Host "Patching module manifest file $outputManifestFile" -ForegroundColor Green + if ($env:BHBuildSystem -eq 'AppVeyor') { + # If we're in AppVeyor, add the build number to the manifest + Write-Host "* Updating build number" -ForegroundColor Green + + $manifestContent = Get-Content -Path $outputManifestFile -Raw + $manifestContent = $manifestContent -replace '(?<=ModuleVersion\s+=\s+'')(?.*)(?='')', + ('${{ModuleVersion}}.{0}' -f $env:APPVEYOR_BUILD_NUMBER) + + Update-Metadata -Path $outputManifestFile -PropertyName ModuleVersion -Value $Version + } + + Write-Host "Defining module functions" -ForegroundColor Green + Set-ModuleFunctions -Name (Join-Path $OutDir -ChildPath 'PSJira\PSJira.psd1') +} + +############################################################################### +# Customize these tasks for performing operations before and/or after Test. +############################################################################### + +# Executes before the Test task. +Task BeforeTest { +} + +# Executes after the Test task. +Task AfterTest -requiredVariables TestOutputFile { + if ($env:BHBuildSystem -eq 'AppVeyor') { + # Upload test results to AppVeyor + + if (-not (Test-Path $TestOutputFile)) { + throw "Pester test file was not created at path $TestOutputFile. Build cannot continue." + } + + $url = "https://ci.appveyor.com/api/testresults/nunit/$env:APPVEYOR_JOB_ID" + Write-Host "Uploading test results back to AppVeyor, url=[$url]" + $wc = New-Object -TypeName System.Net.WebClient + $wc.UploadFile($url, $TestOutputFile) + $wc.Dispose() + } +} + +############################################################################### +# Customize these tasks for performing operations before and/or after BuildHelp. +############################################################################### + +# Executes before the BuildHelp task. +Task BeforeBuildHelp { +} + +# Executes after the BuildHelp task. +Task AfterBuildHelp { +} + +############################################################################### +# Customize these tasks for performing operations before and/or after BuildUpdatableHelp. +############################################################################### + +# Executes before the BuildUpdatableHelp task. +Task BeforeBuildUpdatableHelp { +} + +# Executes after the BuildUpdatableHelp task. +Task AfterBuildUpdatableHelp { +} + +############################################################################### +# Customize these tasks for performing operations before and/or after GenerateFileCatalog. +############################################################################### + +# Executes before the GenerateFileCatalog task. +Task BeforeGenerateFileCatalog { +} + +# Executes after the GenerateFileCatalog task. +Task AfterGenerateFileCatalog { +} + +############################################################################### +# Customize these tasks for performing operations before and/or after Install. +############################################################################### + +# Executes before the Install task. +Task BeforeInstall { +} + +# Executes after the Install task. +Task AfterInstall { +} + +############################################################################### +# Customize these tasks for performing operations before and/or after Publish. +############################################################################### + +# Executes before the Publish task. +Task BeforePublish -requiredVariables NuGetApiKey { + if ($env:BHBranchName -ne 'master') { + Write-Host "This build is from branch [$env:BHBranchName]. It will not be published." -ForegroundColor Yellow + throw "Terminating build." + } + + if ($env:BHBuildSystem -eq 'AppVeyor') { + if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { + Write-Host "This build is from a pull request. It will not be published." -ForegroundColor Yellow + throw "Terminating build." + } + + # This build script saves credentials to a CliXML file in $APPDATA. + # While that's useful on a single dev machine, AppVeyor uses + # encrypted credentials in the appveyor.yml file, so we need to + # load those instead. + Write-Host "AppVeyor detected; setting NuGetApiKey to encrypted environment value" + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $NuGetApiKey = $env:PSGalleryAPIKey + } +} + +# Executes after the Publish task. +Task AfterPublish { +} From 9737e7ce48d6ddc623e70352a47b42f7cc263304 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 10:30:49 -0500 Subject: [PATCH 043/102] Fix path to PSake build file --- Tools/Appveyor.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/Appveyor.ps1 b/Tools/Appveyor.ps1 index e317dc61..c4a571a2 100644 --- a/Tools/Appveyor.ps1 +++ b/Tools/Appveyor.ps1 @@ -57,12 +57,12 @@ Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null Install-Module Pester,psake,BuildHelpers -Force # Init the BuildHelpers environment variables -Set-BuildEnvironment +Set-BuildEnvironment -Path $ProjectRoot Write-Host "BuildHelpers environment details:`n$(Get-Item env:BH* | Out-String)`n" -ForegroundColor Cyan Write-Host "Running tests" -ForegroundColor Cyan -Invoke-psake $env:APPVEYOR_BUILD_FOLDER\build\build.psake.ps1 -taskList Test +Invoke-psake -buildFile "$ProjectRoot\build\build.psake.ps1" -taskList Test if (-not $psake.build_success) { Write-Error "Build failed." From 03dce0c76f1c7e32dd15b44951d1560529889e96 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 10:41:31 -0500 Subject: [PATCH 044/102] Remove Set-Location from build script --- build/build.psake.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/build/build.psake.ps1 b/build/build.psake.ps1 index f1c467c7..e068dc8f 100644 --- a/build/build.psake.ps1 +++ b/build/build.psake.ps1 @@ -89,7 +89,6 @@ Task Init -requiredVariables OutDir,ProjectRoot { } Set-BuildEnvironment -Path $ProjectRoot - Set-Location $ProjectRoot } Task Clean -depends Init -requiredVariables OutDir { From 77793e4a62dace94ae12ca472a4575a775c046b5 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 10:49:41 -0500 Subject: [PATCH 045/102] Add debug text to some tasks --- build/build.psake.ps1 | 4 ++++ build/build.settings.ps1 | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/build/build.psake.ps1 b/build/build.psake.ps1 index e068dc8f..964bece7 100644 --- a/build/build.psake.ps1 +++ b/build/build.psake.ps1 @@ -62,6 +62,7 @@ # Private properties. ############################################################################### Properties { + Write-Host "build.psake.ps1 - Properties" -ForegroundColor Green [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $ModuleOutDir = "$OutDir\$ModuleName" @@ -81,6 +82,7 @@ Properties { Task default -depends Build Task Init -requiredVariables OutDir,ProjectRoot { + Write-Host "build.psake.ps1 - Init" -ForegroundColor Green if (!(Test-Path -LiteralPath $OutDir)) { New-Item $OutDir -ItemType Directory -Verbose:$VerbosePreference > $null } @@ -92,6 +94,7 @@ Task Init -requiredVariables OutDir,ProjectRoot { } Task Clean -depends Init -requiredVariables OutDir { + Write-Host "build.psake.ps1 - Clean" -ForegroundColor Green # Maybe a bit paranoid but this task nuked \ on my laptop. Good thing I was not running as admin. if ($OutDir.Length -gt 3) { Get-ChildItem $OutDir | Remove-Item -Recurse -Force -Verbose:$VerbosePreference @@ -105,6 +108,7 @@ Task StageFiles -depends Init, Clean, BeforeStageFiles, CoreStageFiles, AfterSta } Task CoreStageFiles -requiredVariables ModuleOutDir, SrcRootDir { + Write-Host "build.psake.ps1 - CoreStageFiles" -ForegroundColor Green if (!(Test-Path -LiteralPath $ModuleOutDir)) { New-Item $ModuleOutDir -ItemType Directory -Verbose:$VerbosePreference > $null } diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index 35fc6216..f805ac34 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -5,6 +5,8 @@ Properties { # ----------------------- Basic properties -------------------------------- + Write-Host "build.settings.ps1 - Propertes" -ForegroundColor Green + # Root directory for the project $ProjectRoot = Split-Path $PSScriptRoot -Parent @@ -143,6 +145,8 @@ Properties { # a path. This parameter is passed through to Invoke-Pester's -OutputFormat parameter. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $TestOutputFormat = "NUnitXml" + + Write-Host "build.settings.ps1 - Propertes completed" -ForegroundColor Green } ############################################################################### @@ -151,6 +155,7 @@ Properties { # Executes before the StageFiles task. Task BeforeStageFiles -requiredVariables ProjectRoot { + Write-Host "build.settings.ps1 - BeforeStageFiles" -ForegroundColor Green Write-Host "BuildHelpers environment:`n$(Get-Item env:bh* | Out-String)" -ForegroundColor Green } @@ -164,6 +169,7 @@ Task AfterStageFiles { # Executes before the BeforeStageFiles phase of the Build task. Task BeforeBuild { + Write-Host "build.settings.ps1 - BeforeBuild" -ForegroundColor Green } # Executes after the Build task. From e311a2f749590f921871b483d8df8c9662fd61b0 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 11:16:32 -0500 Subject: [PATCH 046/102] Add additional debug text AppVeyor is again failing on something that I can't reproduce. I'm using debug text to try to identify the failure. --- build/build.settings.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index f805ac34..75fa12c2 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -5,10 +5,12 @@ Properties { # ----------------------- Basic properties -------------------------------- - Write-Host "build.settings.ps1 - Propertes" -ForegroundColor Green + Write-Host "build.settings.ps1 - Properties" -ForegroundColor Green + Write-Host "* PSScriptRoot: $PSScriptRoot" -ForegroundColor Green # Root directory for the project - $ProjectRoot = Split-Path $PSScriptRoot -Parent + $ProjectRoot = Split-Path "$PSScriptRoot" -Parent + Write-Host "* ProjectRoot: $ProjectRoot" -ForegroundColor Green # The root directories for the module's docs, src and test. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] @@ -22,15 +24,18 @@ Properties { $ModuleName = Get-Item $SrcRootDir/*.psd1 | Where-Object { $null -ne (Test-ModuleManifest -Path $_ -ErrorAction SilentlyContinue) } | Select-Object -First 1 | Foreach-Object BaseName + Write-Host "* ModuleName: $ModuleName" -ForegroundColor Green # The $OutDir is where module files and updatable help files are staged for signing, install and publishing. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $OutDir = "$ProjectRoot\Release" + Write-Host "* OutDir: $OutDir" -ForegroundColor Green # The local installation directory for the install task. Defaults to your home Modules location. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $InstallPath = Join-Path (Split-Path $profile.CurrentUserAllHosts -Parent) ` "Modules\$ModuleName\$((Test-ModuleManifest -Path $SrcRootDir\$ModuleName.psd1).Version.ToString())" + Write-Host "* InstallPath: $InstallPath" -ForegroundColor Green # Default Locale used for help generation, defaults to en-US. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] From dadafa9e0a8b5e2d078de0f97239ab72d34080b8 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 12:05:08 -0500 Subject: [PATCH 047/102] Add checking for $profile var --- build/build.settings.ps1 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index 75fa12c2..3458cecc 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -32,9 +32,16 @@ Properties { Write-Host "* OutDir: $OutDir" -ForegroundColor Green # The local installation directory for the install task. Defaults to your home Modules location. - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] - $InstallPath = Join-Path (Split-Path $profile.CurrentUserAllHosts -Parent) ` - "Modules\$ModuleName\$((Test-ModuleManifest -Path $SrcRootDir\$ModuleName.psd1).Version.ToString())" + if ($profile.CurrentUserAllHosts) { + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $InstallPath = Join-Path (Split-Path $profile.CurrentUserAllHosts -Parent) ` + "Modules\$ModuleName\$((Test-ModuleManifest -Path $SrcRootDir\$ModuleName.psd1).Version.ToString())" + } + else { + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] + $InstallPath = Join-Path $env:USERPROFILE ` + "Documents\WindowsPowerShell\Modules\$ModuleName\$((Test-ModuleManifest -Path $SrcRootDir\$ModuleName.psd1).Version.ToString())" + } Write-Host "* InstallPath: $InstallPath" -ForegroundColor Green # Default Locale used for help generation, defaults to en-US. From 13ce63d6301914daf5025913563ba4f4d8f47c7c Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 12:11:16 -0500 Subject: [PATCH 048/102] Move Set-BuildEnvironment to build.settings.ps1 --- Tools/Appveyor.ps1 | 3 --- build/build.psake.ps1 | 2 -- build/build.settings.ps1 | 1 + 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Tools/Appveyor.ps1 b/Tools/Appveyor.ps1 index c4a571a2..632b975f 100644 --- a/Tools/Appveyor.ps1 +++ b/Tools/Appveyor.ps1 @@ -56,9 +56,6 @@ Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null # Don't forget -Force! Install-Module Pester,psake,BuildHelpers -Force -# Init the BuildHelpers environment variables -Set-BuildEnvironment -Path $ProjectRoot - Write-Host "BuildHelpers environment details:`n$(Get-Item env:BH* | Out-String)`n" -ForegroundColor Cyan Write-Host "Running tests" -ForegroundColor Cyan diff --git a/build/build.psake.ps1 b/build/build.psake.ps1 index 964bece7..bc193fd6 100644 --- a/build/build.psake.ps1 +++ b/build/build.psake.ps1 @@ -89,8 +89,6 @@ Task Init -requiredVariables OutDir,ProjectRoot { else { Write-Verbose "$($psake.context.currentTaskName) - directory already exists '$OutDir'." } - - Set-BuildEnvironment -Path $ProjectRoot } Task Clean -depends Init -requiredVariables OutDir { diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index 3458cecc..a0d986b0 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -159,6 +159,7 @@ Properties { $TestOutputFormat = "NUnitXml" Write-Host "build.settings.ps1 - Propertes completed" -ForegroundColor Green + Set-BuildEnvironment -Path $ProjectRoot } ############################################################################### From e9495e776a20e844392abe22af10730f8aec263d Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 12:27:34 -0500 Subject: [PATCH 049/102] Fix logic to update module version --- Tools/Appveyor.ps1 | 2 +- build/build.settings.ps1 | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Tools/Appveyor.ps1 b/Tools/Appveyor.ps1 index 632b975f..a763bf32 100644 --- a/Tools/Appveyor.ps1 +++ b/Tools/Appveyor.ps1 @@ -54,7 +54,7 @@ Write-Host "AppVeyor build initialized (Job ID $JobId)" -ForegroundColor Cyan Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null # Don't forget -Force! -Install-Module Pester,psake,BuildHelpers -Force +Install-Module Pester,psake,PSScriptAnalyzer,BuildHelpers -Force Write-Host "BuildHelpers environment details:`n$(Get-Item env:BH* | Out-String)`n" -ForegroundColor Cyan diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index a0d986b0..6df5910b 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -194,10 +194,24 @@ Task AfterBuild -requiredVariables ProjectRoot,OutDir { Write-Host "* Updating build number" -ForegroundColor Green $manifestContent = Get-Content -Path $outputManifestFile -Raw - $manifestContent = $manifestContent -replace '(?<=ModuleVersion\s+=\s+'')(?.*)(?='')', - ('${{ModuleVersion}}.{0}' -f $env:APPVEYOR_BUILD_NUMBER) + if ($manifestContent -notmatch '(?<=ModuleVersion\s+=\s+'')(?.*)(?='')') { + throw "Module version was not found in manifest file $outputManifestFile" + } + + $currentVersion = [Version] $Matches.ModuleVersion + if ($env:BHBuildNumber) { + $newRevision = $env:BHBuildNumber + } + else { + $newRevision = $currentVersion.Revision + } + + $newVersion = New-Object -TypeName System.Version -ArgumentList $currentVersion.Major, + $currentVersion.Minor, + $currentVersion.Build, + $newRevision - Update-Metadata -Path $outputManifestFile -PropertyName ModuleVersion -Value $Version + Update-Metadata -Path $outputManifestFile -PropertyName ModuleVersion -Value $newVersion } Write-Host "Defining module functions" -ForegroundColor Green From c644e10d8dd10d7241dddd669dd4b3b09b200a38 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 12:45:03 -0500 Subject: [PATCH 050/102] Fix path and remove Write-Hosts --- build/build.psake.ps1 | 4 ---- build/build.settings.ps1 | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/build/build.psake.ps1 b/build/build.psake.ps1 index bc193fd6..d9b74d3d 100644 --- a/build/build.psake.ps1 +++ b/build/build.psake.ps1 @@ -62,7 +62,6 @@ # Private properties. ############################################################################### Properties { - Write-Host "build.psake.ps1 - Properties" -ForegroundColor Green [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $ModuleOutDir = "$OutDir\$ModuleName" @@ -82,7 +81,6 @@ Properties { Task default -depends Build Task Init -requiredVariables OutDir,ProjectRoot { - Write-Host "build.psake.ps1 - Init" -ForegroundColor Green if (!(Test-Path -LiteralPath $OutDir)) { New-Item $OutDir -ItemType Directory -Verbose:$VerbosePreference > $null } @@ -92,7 +90,6 @@ Task Init -requiredVariables OutDir,ProjectRoot { } Task Clean -depends Init -requiredVariables OutDir { - Write-Host "build.psake.ps1 - Clean" -ForegroundColor Green # Maybe a bit paranoid but this task nuked \ on my laptop. Good thing I was not running as admin. if ($OutDir.Length -gt 3) { Get-ChildItem $OutDir | Remove-Item -Recurse -Force -Verbose:$VerbosePreference @@ -106,7 +103,6 @@ Task StageFiles -depends Init, Clean, BeforeStageFiles, CoreStageFiles, AfterSta } Task CoreStageFiles -requiredVariables ModuleOutDir, SrcRootDir { - Write-Host "build.psake.ps1 - CoreStageFiles" -ForegroundColor Green if (!(Test-Path -LiteralPath $ModuleOutDir)) { New-Item $ModuleOutDir -ItemType Directory -Verbose:$VerbosePreference > $null } diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index 6df5910b..4aefc306 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -17,7 +17,7 @@ Properties { $DocsRootDir = "$ProjectRoot\docs" $SrcRootDir = "$ProjectRoot\PSJira" [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] - $TestRootDir = "$ProjectRoot\test" + $TestRootDir = "$ProjectRoot\Tests" # The name of your module should match the basename of the PSD1 file. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] From a128b08bb9e906cf0f58acb1abc427f60e4bf250 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 14:33:49 -0500 Subject: [PATCH 051/102] Move Pester result upload to Appveyor.ps1 PSake was causing the job to fail before it reached the AfterTest task where I'd been trying to upload task results. Moving this back to Appveyor.ps1 should cause it to run correctly even when psake exits with an error. This commit also removes the changes I'd made to build.psake.ps1 (changing Test to CoreTest to enable a BeforeTest and AfterTest task in build.settings.ps1). Those tasks are probably not necessary, and I'd like to keep build.psake.ps1 as close to the template as possible. --- Tools/Appveyor.ps1 | 12 ++++++++++++ build/build.psake.ps1 | 5 +---- build/build.settings.ps1 | 29 ++--------------------------- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/Tools/Appveyor.ps1 b/Tools/Appveyor.ps1 index a763bf32..396540a5 100644 --- a/Tools/Appveyor.ps1 +++ b/Tools/Appveyor.ps1 @@ -61,6 +61,18 @@ Write-Host "BuildHelpers environment details:`n$(Get-Item env:BH* | Out-String)` Write-Host "Running tests" -ForegroundColor Cyan Invoke-psake -buildFile "$ProjectRoot\build\build.psake.ps1" -taskList Test +# Make sure this matches the declaration in build.settings.ps1 +$testOutputFile = Join-Path $ProjectRoot 'TestResults.xml' +if (-not (Test-Path $testOutputFile)) { + throw "Test results were not found at path " +} + +$url = "https://ci.appveyor.com/api/testresults/nunit/$env:APPVEYOR_JOB_ID" +Write-Host "Uploading test results back to AppVeyor, url=[$url]" +$wc = New-Object -TypeName System.Net.WebClient +$wc.UploadFile($url, $testOutputFile) +$wc.Dispose() + if (-not $psake.build_success) { Write-Error "Build failed." exit 1 diff --git a/build/build.psake.ps1 b/build/build.psake.ps1 index d9b74d3d..ec2d11d9 100644 --- a/build/build.psake.ps1 +++ b/build/build.psake.ps1 @@ -380,10 +380,7 @@ Task CoreInstall -requiredVariables ModuleOutDir { "Module installed into $InstallPath" } -Task Test -depends Build, BeforeTest, CoreTest, AfterTest { -} - -Task CoreTest -depends Build -requiredVariables TestRootDir, ModuleName, CodeCoverageEnabled, CodeCoverageFiles { +Task Test -depends Build -requiredVariables TestRootDir, ModuleName, CodeCoverageEnabled, CodeCoverageFiles { if (!(Get-Module Pester -ListAvailable)) { "Pester module is not installed. Skipping $($psake.context.currentTaskName) task." return diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index 4aefc306..23ce6bab 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -151,7 +151,7 @@ Properties { # This is typically used to write out test results so that they can be sent to a CI # system like AppVeyor. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] - $TestOutputFile = "$env:TEMP\TestResults_PS$PSVersion`_$TimeStamp.xml" + $TestOutputFile = "$ProjectRoot\TestResults.xml" # Specifies the test output format to use when the TestOutputFile property is given # a path. This parameter is passed through to Invoke-Pester's -OutputFormat parameter. @@ -215,32 +215,7 @@ Task AfterBuild -requiredVariables ProjectRoot,OutDir { } Write-Host "Defining module functions" -ForegroundColor Green - Set-ModuleFunctions -Name (Join-Path $OutDir -ChildPath 'PSJira\PSJira.psd1') -} - -############################################################################### -# Customize these tasks for performing operations before and/or after Test. -############################################################################### - -# Executes before the Test task. -Task BeforeTest { -} - -# Executes after the Test task. -Task AfterTest -requiredVariables TestOutputFile { - if ($env:BHBuildSystem -eq 'AppVeyor') { - # Upload test results to AppVeyor - - if (-not (Test-Path $TestOutputFile)) { - throw "Pester test file was not created at path $TestOutputFile. Build cannot continue." - } - - $url = "https://ci.appveyor.com/api/testresults/nunit/$env:APPVEYOR_JOB_ID" - Write-Host "Uploading test results back to AppVeyor, url=[$url]" - $wc = New-Object -TypeName System.Net.WebClient - $wc.UploadFile($url, $TestOutputFile) - $wc.Dispose() - } + Set-ModuleFunctions -Name $outputManifestFile } ############################################################################### From 6c28f4ddf0410b8ac46279ab974c75554af4cbdf Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 22 May 2017 16:14:27 -0500 Subject: [PATCH 052/102] Remove remaing Write-Debug These Write-Debug statements are commented out because they can be extremely annoying when debugging other issues. They can be restored if there are issues with the specific ConvertTo-* function. This cleans up a Write-Debug that missed getting commented out earlier. --- PSJira/Internal/ConvertTo-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/Internal/ConvertTo-JiraIssue.ps1 b/PSJira/Internal/ConvertTo-JiraIssue.ps1 index 7470dbfe..439d7b66 100644 --- a/PSJira/Internal/ConvertTo-JiraIssue.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssue.ps1 @@ -120,7 +120,7 @@ function ConvertTo-JiraIssue } } - Write-Debug "[ConvertTo-JiraIssue] Checking for any additional fields" +# Write-Debug "[ConvertTo-JiraIssue] Checking for any additional fields" $extraFields = $i.fields.PSObject.Properties | Where-Object -FilterScript { $_.Name -notin $props.Keys } foreach ($f in $extraFields) { From 3a2add7f34cffc0b396ceb1079551b1a7380a811 Mon Sep 17 00:00:00 2001 From: Michael Dejulia Date: Mon, 22 May 2017 14:25:38 -0700 Subject: [PATCH 053/102] Issue #40, FixVersion Param --- PSJira/Public/Set-JiraIssue.ps1 | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/PSJira/Public/Set-JiraIssue.ps1 b/PSJira/Public/Set-JiraIssue.ps1 index d6d24857..00869fba 100644 --- a/PSJira/Public/Set-JiraIssue.ps1 +++ b/PSJira/Public/Set-JiraIssue.ps1 @@ -41,6 +41,10 @@ function Set-JiraIssue [Parameter(Mandatory = $false)] [String] $Description, + # New FixVersion of the issue + [Parameter(Mandatory = $false)] + [System.Collections.Hashtable] $FixVersion, + # New assignee of the issue. Enter 'Unassigned' to unassign the issue. [Parameter(Mandatory = $false)] [Object] $Assignee, @@ -67,7 +71,7 @@ function Set-JiraIssue { Write-Debug "[Set-JiraIssue] Checking to see if we have any operations to perform" $fieldNames = $Fields.Keys - if (-not ($Summary -or $Description -or $Assignee -or $Label -or $fieldNames)) + if (-not ($Summary -or $Description -or $Assignee -or $Label -or $FixVersion -or $fieldNames)) { Write-Verbose "Nothing to do." return @@ -137,6 +141,15 @@ function Set-JiraIssue $actOnIssueUri = $true } + If($FixVersion) + { + $issueProps.update.fixVersions = @() + $issueProps.update.fixVersions += @{ + 'add' = $FixVersion; + } + $actOnIssueUri = $true + } + if ($Fields) { Write-Debug "[Set-JiraIssue] Validating field names" @@ -168,7 +181,6 @@ function Set-JiraIssue if ($validAssignee) { - $assigneeProps = @{ 'name' = $assigneeString; } @@ -213,7 +225,6 @@ function Set-JiraIssue Write-Debug "[Set-JiraIssue] PassThru was specified. Obtaining updated reference to issue" Get-JiraIssue -Key $issueObj.Key -Credential $Credential } - } else { Write-Debug "[Set-JiraIssue] Unable to identify issue [$i]. Writing error message." Write-Error "Unable to identify issue [$i]" @@ -225,6 +236,4 @@ function Set-JiraIssue { Write-Debug "[Set-JiraIssue] Complete" } -} - - +} \ No newline at end of file From a3c53a2a2c27cdbb16d4ae037c158e41c3ee5af9 Mon Sep 17 00:00:00 2001 From: Michael Dejulia Date: Mon, 22 May 2017 14:41:18 -0700 Subject: [PATCH 054/102] #40 FixVersion Param End new line --- PSJira/Public/Set-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/Public/Set-JiraIssue.ps1 b/PSJira/Public/Set-JiraIssue.ps1 index 00869fba..c96e4035 100644 --- a/PSJira/Public/Set-JiraIssue.ps1 +++ b/PSJira/Public/Set-JiraIssue.ps1 @@ -236,4 +236,4 @@ function Set-JiraIssue { Write-Debug "[Set-JiraIssue] Complete" } -} \ No newline at end of file +} From 4d502c963fdc4d9b07d43a240ecd25462461bb94 Mon Sep 17 00:00:00 2001 From: Michael Dejulia Date: Tue, 23 May 2017 08:04:01 -0700 Subject: [PATCH 055/102] Issue #40, FixVersion Param Set-JiraIssue, New-JiraIssue, Alias('FixVersions'), Set in replace of Add --- PSJira/Public/New-JiraIssue.ps1 | 19 +++++++++++++++++++ PSJira/Public/Set-JiraIssue.ps1 | 14 +++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index 29f7cdc3..3826e021 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -53,6 +53,11 @@ function New-JiraIssue [Parameter(Mandatory = $false)] [String] $Parent, + # Set the FixVersion of the issue + [Parameter(Mandatory = $false)] + [Alias('FixVersions')] + [String[]] $FixVersion, + [Parameter(Mandatory = $false)] [Hashtable] $Fields, @@ -123,6 +128,20 @@ function New-JiraIssue [void] $props.Add('labels', $Labels) } + Write-Debug "[New-JiraIssue] Processing FixVersion parameter" + If($FixVersion) + { + $fixVersionHash = @() + Foreach($f in $FixVersion) + { + $fixVersionHash += @{ + 'name' = $f + } + } + $props.fixVersions = New-Object -TypeName PSObject -Property @{} + $props.fixVersions = $fixVersionHash + } + Write-Debug "[New-JiraIssue] Processing Fields parameter" foreach ($k in $Fields.Keys) { diff --git a/PSJira/Public/Set-JiraIssue.ps1 b/PSJira/Public/Set-JiraIssue.ps1 index c96e4035..4397a17d 100644 --- a/PSJira/Public/Set-JiraIssue.ps1 +++ b/PSJira/Public/Set-JiraIssue.ps1 @@ -41,9 +41,10 @@ function Set-JiraIssue [Parameter(Mandatory = $false)] [String] $Description, - # New FixVersion of the issue + # Set the FixVersion of the issue, this will overwrite any present FixVersions [Parameter(Mandatory = $false)] - [System.Collections.Hashtable] $FixVersion, + [Alias('FixVersions')] + [String[]] $FixVersion, # New assignee of the issue. Enter 'Unassigned' to unassign the issue. [Parameter(Mandatory = $false)] @@ -143,9 +144,16 @@ function Set-JiraIssue If($FixVersion) { + $fixVersionSet = @() + Foreach($f in $FixVersion) + { + $fixVersionSet += @{ + 'name' = $f + } + } $issueProps.update.fixVersions = @() $issueProps.update.fixVersions += @{ - 'add' = $FixVersion; + 'set' = $fixVersionSet; } $actOnIssueUri = $true } From 3c58908262cd12af50880053b4dac1e812f6958b Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 24 May 2017 11:29:47 +0200 Subject: [PATCH 056/102] Take over global PSDefaultParameterValues from global scope to local, so that nested function will use the same PSDefaultParameterValues closes #97 --- PSJira/Internal/Invoke-JiraMethod.ps1 | 5 +++++ PSJira/Public/New-JiraSession.ps1 | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/PSJira/Internal/Invoke-JiraMethod.ps1 b/PSJira/Internal/Invoke-JiraMethod.ps1 index 4450d1f1..8796fcfe 100644 --- a/PSJira/Internal/Invoke-JiraMethod.ps1 +++ b/PSJira/Internal/Invoke-JiraMethod.ps1 @@ -23,6 +23,11 @@ function Invoke-JiraMethod # [Object] $Session ) + # load DefaultParameters for Invoke-WebRequest + # as the global PSDefaultParameterValues is not used + # TODO: find out why PSJira doesn't need this + $PSDefaultParameterValues = $global:PSDefaultParameterValues + $headers = @{ 'Content-Type' = 'application/json; charset=utf-8'; } diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index fa7dbd4a..2d26c9cd 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -42,6 +42,10 @@ function New-JiraSession throw $err } + # load DefaultParameters for Invoke-WebRequest + # as the global PSDefaultParameterValues is not used + $PSDefaultParameterValues = $global:PSDefaultParameterValues + $uri = "$server/rest/auth/1/session" $headers = @{ From d83b9c7d133f6eda20f9fb9f0ec811c141606143 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 24 May 2017 11:55:30 +0200 Subject: [PATCH 057/102] Add test if headers contain info that captcha is required implements #107 --- PSJira/Public/New-JiraSession.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index 2d26c9cd..172a8809 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -89,6 +89,13 @@ function New-JiraSession $webResponse = $err.Exception.Response Write-Debug "[New-JiraSession] Encountered an exception from the Jira server: $err" + # Test HEADERS if Jira requires a CAPTCHA + $tokenRequiresCaptcha = "AUTHENTICATED_FAILED" + $headerRequiresCaptcha = "X-Seraph-LoginReason" + if (($webResponse.headers[$headerRequiresCaptcha] -split ",") -contains $tokenRequiresCaptcha) { + Write-Warning "JIRA requires you to log on to the website before continiuing for security reasons." + } + Write-Warning "JIRA returned HTTP error $($webResponse.StatusCode.value__) - $($webResponse.StatusCode)" # Retrieve body of HTTP response - this contains more useful information about exactly why the error From d5d2fcd0ca6e5259bec0231c69e712c4ba6c4952 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 24 May 2017 19:08:40 +0200 Subject: [PATCH 058/102] Fix trailing whitespace --- PSJira/Public/Invoke-JiraIssueTransition.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PSJira/Public/Invoke-JiraIssueTransition.ps1 b/PSJira/Public/Invoke-JiraIssueTransition.ps1 index d920fedb..2d04d65b 100644 --- a/PSJira/Public/Invoke-JiraIssueTransition.ps1 +++ b/PSJira/Public/Invoke-JiraIssueTransition.ps1 @@ -143,7 +143,7 @@ function Invoke-JiraIssueTransition if ($validAssignee) { - Write-Debug "[Invoke-JiraIssueTransition] Updating Assignee" + Write-Debug "[Invoke-JiraIssueTransition] Updating Assignee" $props += @{ 'fields' = @{ 'assignee' = @{ @@ -152,15 +152,15 @@ function Invoke-JiraIssueTransition } } } - + if ($Fields) { - Write-Debug "[Invoke-JiraIssueTransition] Validating field names" + Write-Debug "[Invoke-JiraIssueTransition] Validating field names" $props += @{ 'update' = @{} } - + foreach ($k in $Fields.Keys) { $name = $k From 256f2195177ef1e45a7e05c19c7d054ffae4b0af Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Fri, 26 May 2017 11:48:13 -0700 Subject: [PATCH 059/102] Relocated tests to .\Tests subdir --- {PSJira/Public => Tests}/Add-JiraIssueWorklog.Tests.ps1 | 0 {PSJira/Internal => Tests}/ConvertTo-JiraWorklogitem.Tests.ps1 | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {PSJira/Public => Tests}/Add-JiraIssueWorklog.Tests.ps1 (100%) rename {PSJira/Internal => Tests}/ConvertTo-JiraWorklogitem.Tests.ps1 (100%) diff --git a/PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 b/Tests/Add-JiraIssueWorklog.Tests.ps1 similarity index 100% rename from PSJira/Public/Add-JiraIssueWorklog.Tests.ps1 rename to Tests/Add-JiraIssueWorklog.Tests.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraWorklogitem.Tests.ps1 b/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 similarity index 100% rename from PSJira/Internal/ConvertTo-JiraWorklogitem.Tests.ps1 rename to Tests/ConvertTo-JiraWorklogitem.Tests.ps1 From 97bebe58574c967a21403ee81e5126e44c04cbd1 Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Fri, 26 May 2017 11:56:53 -0700 Subject: [PATCH 060/102] Updated top of Add-JiraIssueWorking.Tests.ps1 to use $PSScriptRoot\Shared.ps1 like other tests. --- Tests/Add-JiraIssueWorklog.Tests.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tests/Add-JiraIssueWorklog.Tests.ps1 b/Tests/Add-JiraIssueWorklog.Tests.ps1 index 993f30f7..2356a155 100644 --- a/Tests/Add-JiraIssueWorklog.Tests.ps1 +++ b/Tests/Add-JiraIssueWorklog.Tests.ps1 @@ -1,6 +1,4 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { From 581b2a8aa55c955615c66f7e27c4c9b5867c7b33 Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Fri, 26 May 2017 12:06:54 -0700 Subject: [PATCH 061/102] Missed a reference to Shared.ps1 --- Tests/ConvertTo-JiraWorklogitem.Tests.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 b/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 index 21358932..57707951 100644 --- a/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 +++ b/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 @@ -1,6 +1,4 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { Describe "ConvertTo-JiraWorklogitem" { From 9bbddbee866290d7b9da23569a4ed5c3d246530a Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 28 May 2017 08:05:12 +0200 Subject: [PATCH 062/102] Use Basic Authentication to generate session Using Basic Authentication fixes problems mentioned in #87 and #107 --- PSJira/Public/New-JiraSession.ps1 | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index fa7dbd4a..5773ceb5 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -42,30 +42,26 @@ function New-JiraSession throw $err } - $uri = "$server/rest/auth/1/session" + $uri = "$server/rest/api/2/mypermissions" $headers = @{ 'Content-Type' = 'application/json'; } } - process - { - $hashtable = @{ - 'username' = $Credential.UserName; - 'password' = $Credential.GetNetworkCredential().Password; - } - $json = ConvertTo-Json -InputObject $hashtable + process { + [String] $Username = $Credential.UserName + $token = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("${Username}:$($Credential.GetNetworkCredential().Password)")) + $headers.Add('Authorization', "Basic $token") - Write-Debug "[New-JiraSession] Created JSON syntax in variable `$json." - Write-Debug "[New-JiraSession] Preparing for blastoff!" + try { + Write-Debug "[New-JiraSession] Preparing for blastoff!" + $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -Body $json -UseBasicParsing -SessionVariable newSessionVar - try - { - $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Post -Body $json -UseBasicParsing -SessionVariable newSessionVar Write-Debug "[New-JiraSession] Converting result to JiraSession object" $result = ConvertTo-JiraSession -WebResponse $webResponse -Session $newSessionVar -Username $Credential.UserName + Write-Debug "[New-JiraSession] Saving session in module's PrivateData" if ($MyInvocation.MyCommand.Module.PrivateData) { From 88b17cdb46cd51e49e48c80b7bcfab4620c2d2cc Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 6 Jun 2017 14:40:55 +0200 Subject: [PATCH 063/102] fix the value of the header information --- PSJira/Public/New-JiraSession.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index 172a8809..ccbc9705 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -90,9 +90,9 @@ function New-JiraSession Write-Debug "[New-JiraSession] Encountered an exception from the Jira server: $err" # Test HEADERS if Jira requires a CAPTCHA - $tokenRequiresCaptcha = "AUTHENTICATED_FAILED" + $tokenRequiresCaptcha = "AUTHENTICATION_DENIED" $headerRequiresCaptcha = "X-Seraph-LoginReason" - if (($webResponse.headers[$headerRequiresCaptcha] -split ",") -contains $tokenRequiresCaptcha) { + if (($webResponse.Headers[$headerRequiresCaptcha] -split ",") -contains $tokenRequiresCaptcha) { Write-Warning "JIRA requires you to log on to the website before continiuing for security reasons." } From cb256a8c5d5e7aad54560489d7ee9a801ec73f98 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 6 Jun 2017 14:44:19 +0200 Subject: [PATCH 064/102] Send credentials as parameter rather than in the headers --- PSJira/Public/New-JiraSession.ps1 | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index b6bc0ac2..144134e8 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -1,5 +1,4 @@ -function New-JiraSession -{ +function New-JiraSession { <# .Synopsis Creates a persistent JIRA authenticated session which can be used by other PSJira functions @@ -26,14 +25,12 @@ function New-JiraSession param( # Credentials to use for the persistent session [Parameter(Mandatory = $true, - Position = 0)] + Position = 0)] [System.Management.Automation.PSCredential] $Credential ) - begin - { - try - { + begin { + try { Write-Debug "[New-JiraSession] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop } catch { @@ -43,7 +40,7 @@ function New-JiraSession } $uri = "$server/rest/api/2/mypermissions" - + # load DefaultParameters for Invoke-WebRequest # as the global PSDefaultParameterValues is not used $PSDefaultParameterValues = $global:PSDefaultParameterValues @@ -55,24 +52,19 @@ function New-JiraSession } process { - [String] $Username = $Credential.UserName - $token = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("${Username}:$($Credential.GetNetworkCredential().Password)")) - $headers.Add('Authorization', "Basic $token") - try { Write-Debug "[New-JiraSession] Preparing for blastoff!" - $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -Body $json -UseBasicParsing -SessionVariable newSessionVar + $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -Body $json -Credential $Credential -UseBasicParsing -SessionVariable newSessionVar Write-Debug "[New-JiraSession] Converting result to JiraSession object" $result = ConvertTo-JiraSession -WebResponse $webResponse -Session $newSessionVar -Username $Credential.UserName - Write-Debug "[New-JiraSession] Saving session in module's PrivateData" - if ($MyInvocation.MyCommand.Module.PrivateData) - { + if ($MyInvocation.MyCommand.Module.PrivateData) { Write-Debug "[New-JiraSession] Adding session result to existing module PrivateData" $MyInvocation.MyCommand.Module.PrivateData.Session = $result; - } else { + } + else { Write-Debug "[New-JiraSession] Creating module PrivateData" $MyInvocation.MyCommand.Module.PrivateData = @{ 'Session' = $result; From 021c4e48fd38ca1c36cbececc5b66ffe156da0cc Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 6 Jun 2017 14:45:22 +0200 Subject: [PATCH 065/102] Handle response body that is HTML --- PSJira/Public/New-JiraSession.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index 144134e8..f1449cb7 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -86,6 +86,10 @@ function New-JiraSession { $body = $readStream.ReadToEnd() $readStream.Close() Write-Debug "Retrieved body of HTTP response for more information about the error (`$body)" + + # Clear the body in case it is not a JSON (but rather html) + if ($body -match "^[\s\t]*\") { $body = "" } + $result = ConvertFrom-Json2 -InputObject $body Write-Debug "Converted body from JSON into PSCustomObject (`$result)" } From 72c0f712949321156be83283509f332d9c3564bc Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 6 Jun 2017 14:49:08 +0200 Subject: [PATCH 066/102] Fix Typo --- PSJira/Public/New-JiraSession.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index ccbc9705..ec346828 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -93,7 +93,7 @@ function New-JiraSession $tokenRequiresCaptcha = "AUTHENTICATION_DENIED" $headerRequiresCaptcha = "X-Seraph-LoginReason" if (($webResponse.Headers[$headerRequiresCaptcha] -split ",") -contains $tokenRequiresCaptcha) { - Write-Warning "JIRA requires you to log on to the website before continiuing for security reasons." + Write-Warning "JIRA requires you to log on to the website before continuing for security reasons." } Write-Warning "JIRA returned HTTP error $($webResponse.StatusCode.value__) - $($webResponse.StatusCode)" From ad0bbf44fd86315f419c8ae87637ac942c805c18 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 6 Jun 2017 15:33:05 +0200 Subject: [PATCH 067/102] Fix Unit Tests --- Tests/New-JiraSession.Tests.ps1 | 6 +++--- Tests/Remove-JiraSession.Tests.ps1 | 28 +++++++++++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Tests/New-JiraSession.Tests.ps1 b/Tests/New-JiraSession.Tests.ps1 index 63169bfa..693209ed 100644 --- a/Tests/New-JiraSession.Tests.ps1 +++ b/Tests/New-JiraSession.Tests.ps1 @@ -12,7 +12,7 @@ InModuleScope PSJira { . $PSScriptRoot\Shared.ps1 $jiraServer = 'http://jiraserver.example.com' - $authUri = "$jiraServer/rest/auth/1/session" + $authUri = "$jiraServer/rest/api/2/mypermissions" $jSessionId = '76449957D8C863BE8D4F6F5507E980E8' $testUsername = 'powershell-test' @@ -40,10 +40,10 @@ InModuleScope PSJira { Write-Output $jiraServer } - Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'POST'} { + Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'GET'} { if ($showMockData) { - Write-Host " Mocked Invoke-WebRequest with POST method" -ForegroundColor Cyan + Write-Host " Mocked Invoke-WebRequest with GET method" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan Write-Host " [URI] $URI" -ForegroundColor Cyan } diff --git a/Tests/Remove-JiraSession.Tests.ps1 b/Tests/Remove-JiraSession.Tests.ps1 index 992a3451..98d7dc57 100644 --- a/Tests/Remove-JiraSession.Tests.ps1 +++ b/Tests/Remove-JiraSession.Tests.ps1 @@ -12,7 +12,8 @@ InModuleScope PSJira { . $PSScriptRoot\Shared.ps1 $jiraServer = 'http://jiraserver.example.com' - $authUri = "$jiraServer/rest/auth/1/session" + $authUri = "$jiraServer/rest/api/2/mypermissions" + $sessionUri = "$jiraServer/rest/auth/1/session" $jSessionId = '76449957D8C863BE8D4F6F5507E980E8' $testUsername = 'powershell-test' @@ -40,10 +41,10 @@ InModuleScope PSJira { Write-Output $jiraServer } - Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'POST'} { + Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'GET'} { if ($showMockData) { - Write-Host " Mocked Invoke-WebRequest with POST method" -ForegroundColor Cyan + Write-Host " Mocked Invoke-WebRequest with GET method" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan Write-Host " [URI] $URI" -ForegroundColor Cyan } @@ -51,7 +52,7 @@ InModuleScope PSJira { Write-Output $testJson } - Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'DELETE'} { + Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Uri -eq $sessionUri -and $Method -eq 'DELETE'} { if ($showMockData) { Write-Host " Mocked Invoke-WebRequest with DELETE method" -ForegroundColor Cyan @@ -73,22 +74,35 @@ InModuleScope PSJira { # New-JiraSession has some slightly more elaborate testing, which includes a test for Get-JiraSession, # so if both of those pass, they should work as expected here. - New-JiraSession -Credential $testCredential | Remove-JiraSession + New-JiraSession -Credential $testCredential + Get-JiraSession | Should Not BeNullOrEmpty + + Remove-JiraSession + Get-JiraSession | Should BeNullOrEmpty + Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Uri -eq $sessionUri -and $Method -eq 'DELETE'} -Exactly -Times 1 -Scope It + } + + It "Correctly handles sessions from a variable" { + $Session = New-JiraSession -Credential $testCredential + $Session | Should Not BeNullOrEmpty + Get-JiraSession | Should Not BeNullOrEmpty + Remove-JiraSession $Session Get-JiraSession | Should BeNullOrEmpty + Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Uri -eq $sessionUri -and $Method -eq 'DELETE'} -Exactly -Times 1 -Scope It } It "Correctly handles pipeline input from New-JiraSession" { { New-JiraSession -Credential $testCredential | Remove-JiraSession } | Should Not Throw Get-JiraSession | Should BeNullOrEmpty - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'DELETE'} -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Uri -eq $sessionUri -and $Method -eq 'DELETE'} -Exactly -Times 1 -Scope It } It "Correctly handles pipeline input from Get-JiraSession" { New-JiraSession -Credential $testCredential { Get-JiraSession | Remove-JiraSession } | Should Not Throw Get-JiraSession | Should BeNullOrEmpty - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Uri -eq $authUri -and $Method -eq 'DELETE'} -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Uri -eq $sessionUri -and $Method -eq 'DELETE'} -Exactly -Times 1 -Scope It } } } From 9f0dcf36854cfde5e2891feb24391b8140e040d8 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 6 Jun 2017 20:36:22 +0200 Subject: [PATCH 068/102] [regression] Place credentials into headers --- PSJira/Public/New-JiraSession.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index f1449cb7..65a036fb 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -45,16 +45,19 @@ function New-JiraSession { # as the global PSDefaultParameterValues is not used $PSDefaultParameterValues = $global:PSDefaultParameterValues + [String] $Username = $Credential.UserName + $token = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("${Username}:$($Credential.GetNetworkCredential().Password)")) $headers = @{ - 'Content-Type' = 'application/json'; + 'Content-Type' = 'application/json' + 'Authorization' = "Basic $token" } } process { try { Write-Debug "[New-JiraSession] Preparing for blastoff!" - $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -Body $json -Credential $Credential -UseBasicParsing -SessionVariable newSessionVar + $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -Body $json -UseBasicParsing -SessionVariable newSessionVar Write-Debug "[New-JiraSession] Converting result to JiraSession object" $result = ConvertTo-JiraSession -WebResponse $webResponse -Session $newSessionVar -Username $Credential.UserName From 42ea32686f8140df6cec37b185692dbc72c036a9 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 8 Jun 2017 19:20:55 +0200 Subject: [PATCH 069/102] Send ContentType as Parameter instead of in the Header --- PSJira/Internal/Invoke-JiraMethod.ps1 | 5 ++--- PSJira/Public/New-JiraSession.ps1 | 26 ++++++++++++++++---------- Tests/Invoke-JiraMethod.Tests.ps1 | 8 ++++---- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/PSJira/Internal/Invoke-JiraMethod.ps1 b/PSJira/Internal/Invoke-JiraMethod.ps1 index 8796fcfe..0e5a39e7 100644 --- a/PSJira/Internal/Invoke-JiraMethod.ps1 +++ b/PSJira/Internal/Invoke-JiraMethod.ps1 @@ -28,9 +28,7 @@ function Invoke-JiraMethod # TODO: find out why PSJira doesn't need this $PSDefaultParameterValues = $global:PSDefaultParameterValues - $headers = @{ - 'Content-Type' = 'application/json; charset=utf-8'; - } + $headers = @{} if ($Credential) { @@ -56,6 +54,7 @@ function Invoke-JiraMethod Uri = $Uri Headers = $headers Method = $Method + ContentType = 'application/json; charset=utf-8' UseBasicParsing = $true ErrorAction = 'SilentlyContinue' } diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index ec346828..7a0951df 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -48,9 +48,7 @@ function New-JiraSession $uri = "$server/rest/auth/1/session" - $headers = @{ - 'Content-Type' = 'application/json'; - } + $headers = @{} } process @@ -64,18 +62,26 @@ function New-JiraSession Write-Debug "[New-JiraSession] Created JSON syntax in variable `$json." Write-Debug "[New-JiraSession] Preparing for blastoff!" - try - { - $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Post -Body $json -UseBasicParsing -SessionVariable newSessionVar + try { + $iwrSplat = @{ + Uri = $uri + Headers = $headers + Method = "Post" + Body = $json + ContentType = 'application/json; charset=utf-8' + UseBasicParsing = $true + SessionVariable = "newSessionVar" + } + $webResponse = Invoke-WebRequest @iwrSplat Write-Debug "[New-JiraSession] Converting result to JiraSession object" $result = ConvertTo-JiraSession -WebResponse $webResponse -Session $newSessionVar -Username $Credential.UserName Write-Debug "[New-JiraSession] Saving session in module's PrivateData" - if ($MyInvocation.MyCommand.Module.PrivateData) - { + if ($MyInvocation.MyCommand.Module.PrivateData) { Write-Debug "[New-JiraSession] Adding session result to existing module PrivateData" $MyInvocation.MyCommand.Module.PrivateData.Session = $result; - } else { + } + else { Write-Debug "[New-JiraSession] Creating module PrivateData" $MyInvocation.MyCommand.Module.PrivateData = @{ 'Session' = $result; @@ -90,7 +96,7 @@ function New-JiraSession Write-Debug "[New-JiraSession] Encountered an exception from the Jira server: $err" # Test HEADERS if Jira requires a CAPTCHA - $tokenRequiresCaptcha = "AUTHENTICATION_DENIED" + $tokenRequiresCaptcha = "AUTHENTICATION_DENIED" $headerRequiresCaptcha = "X-Seraph-LoginReason" if (($webResponse.Headers[$headerRequiresCaptcha] -split ",") -contains $tokenRequiresCaptcha) { Write-Warning "JIRA requires you to log on to the website before continuing for security reasons." diff --git a/Tests/Invoke-JiraMethod.Tests.ps1 b/Tests/Invoke-JiraMethod.Tests.ps1 index 810d01e3..8191bd77 100644 --- a/Tests/Invoke-JiraMethod.Tests.ps1 +++ b/Tests/Invoke-JiraMethod.Tests.ps1 @@ -50,7 +50,7 @@ InModuleScope PSJira { defParam $command 'Credential' It "Has a ValidateSet for the -Method parameter that accepts methods [$($validMethods -join ', ')]" { - $validateSet = $command.Parameters.Method.Attributes | ? {$_.TypeID -eq [System.Management.Automation.ValidateSetAttribute]} + $validateSet = $command.Parameters.Method.Attributes | Where-Object {$_.TypeID -eq [System.Management.Automation.ValidateSetAttribute]} $validateSet.ValidValues | Should Be $validMethods } } @@ -80,9 +80,9 @@ InModuleScope PSJira { } } - It "Sends the Content-Type header of application/json and UTF-8" { + It "Uses the -ContentType parameter of Invoke-WebRequest to specify application/json and UTF-8" { { Invoke-JiraMethod -Method Get -URI $testUri } | Should Not Throw - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Headers.Item('Content-Type') -eq 'application/json; charset=utf-8'} -Scope It + Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$ContentType -eq 'application/json; charset=utf-8'} -Scope It } It "Uses the -UseBasicParsing switch for Invoke-WebRequest" { @@ -463,7 +463,7 @@ InModuleScope PSJira { $result | Should Not BeNullOrEmpty # Compare each property in the result returned to the expected result - foreach ($property in (Get-Member -InputObject $result | ? {$_.MemberType -eq 'NoteProperty'})) { + foreach ($property in (Get-Member -InputObject $result | Where-Object {$_.MemberType -eq 'NoteProperty'})) { $result.$property | Should Be $validObjResult.$property } } From a41ec30c9a2fce43b6d67f5e0655d690d7918d20 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 11 Jun 2017 13:45:58 +0200 Subject: [PATCH 070/102] Load each function by itself into the runtime recent changes to the dev branch export all functions, including the private ones. In order to exclude them from these test, the module is unloaded and all functions are dot-sourced into the runtime. --- Tests/PSJira.Help.Tests.ps1 | 39 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/Tests/PSJira.Help.Tests.ps1 b/Tests/PSJira.Help.Tests.ps1 index 6d12d108..202faf06 100644 --- a/Tests/PSJira.Help.Tests.ps1 +++ b/Tests/PSJira.Help.Tests.ps1 @@ -103,39 +103,20 @@ function Get-ParametersDefaultFirst END { } } -$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$here = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = Split-Path -Parent $here -$moduleRoot = "$projectRoot\PSJira" - - -# For tests in .\Tests subdirectory -if ((Split-Path $moduleRoot -Leaf) -eq 'Tests') -{ - $moduleRoot = Split-Path $moduleRoot -Parent -} - - -# Handles modules in version directories -$leaf = Split-Path $moduleRoot -Leaf -$parent = Split-Path $moduleRoot -Parent -$parsedVersion = $null -if ([System.Version]::TryParse($leaf, [ref]$parsedVersion)) -{ - $ModuleName = Split-Path $parent -Leaf -} -else -{ - $ModuleName = $leaf -} +$moduleName = "PSJira" +$moduleRoot = "$projectRoot\$moduleName" # Removes all versions of the module from the session before importing -Get-Module $ModuleName | Remove-Module - -# Because ModuleBase includes version number, this imports the required version -# of the module -$Module = Import-Module $moduleRoot\$ModuleName.psd1 -PassThru -ErrorAction Stop -$commands = Get-Command -Module $module -CommandType Cmdlet, Function, Workflow # Not alias +Get-Module $moduleName | Remove-Module +# Dot source all public functions +$commands = @() +Get-ChildItem -Path "$moduleRoot\Public\*.ps1" | ForEach-Object { + . $_.FullName + $commands += Get-Command ($_.BaseName).Replace(".ps1","") +} ## When testing help, remember that help is cached at the beginning of each session. ## To test, restart session. From 89dc69fa227b66fd03e7d7f03edcedbb9b38afdd Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 11 Jun 2017 13:46:49 +0200 Subject: [PATCH 071/102] Update Help from functions * add missing help blocks * add examples for every ParameterSet --- PSJira/Public/Get-JiraIssue.ps1 | 40 +++++++++++++++------------ PSJira/Public/Get-JiraIssueType.ps1 | 23 ++++++++++++++++ PSJira/Public/Get-JiraPriority.ps1 | 18 ++++++++++++ PSJira/Public/New-JiraIssue.ps1 | 3 +- PSJira/Public/Set-JiraIssueLabel.ps1 | 41 ++++++++++++++-------------- 5 files changed, 87 insertions(+), 38 deletions(-) diff --git a/PSJira/Public/Get-JiraIssue.ps1 b/PSJira/Public/Get-JiraIssue.ps1 index 82df0564..1e22cfa9 100644 --- a/PSJira/Public/Get-JiraIssue.ps1 +++ b/PSJira/Public/Get-JiraIssue.ps1 @@ -2,34 +2,40 @@ function Get-JiraIssue { <# .Synopsis - Returns information about an issue in JIRA. + Returns information about an issue in JIRA. .DESCRIPTION - This function obtains references to issues in JIRA. + This function obtains references to issues in JIRA. - This function can be used to directly query JIRA for a specific issue key or internal issue ID. It can also be used to query JIRA for issues matching a specific criteria using JQL (Jira Query Language). + This function can be used to directly query JIRA for a specific issue key or internal issue ID. It can also be used to query JIRA for issues matching a specific criteria using JQL (Jira Query Language). - For more details on JQL syntax, see this articla from Atlassian: https://confluence.atlassian.com/display/JIRA/Advanced+Searching + For more details on JQL syntax, see this articla from Atlassian: https://confluence.atlassian.com/display/JIRA/Advanced+Searching - Output from this function can be piped to various other functions in this module, including Set-JiraIssue, Add-JiraIssueComment, and Invoke-JiraIssueTransition. + Output from this function can be piped to various other functions in this module, including Set-JiraIssue, Add-JiraIssueComment, and Invoke-JiraIssueTransition. .EXAMPLE - Get-JiraIssue -Key TEST-001 - This example returns a reference to JIRA issue TEST-001. + Get-JiraIssue -Key TEST-001 + This example returns a reference to JIRA issue TEST-001. .EXAMPLE - Get-JiraIssue "TEST-002" | Add-JiraIssueComment "Test comment from PowerShell" - This example illustrates pipeline use from Get-JiraIssue to Add-JiraIssueComment. + Get-JiraIssue "TEST-002" | Add-JiraIssueComment "Test comment from PowerShell" + This example illustrates pipeline use from Get-JiraIssue to Add-JiraIssueComment. .EXAMPLE - Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' - This example illustrates using the Query parameter and JQL syntax to query Jira for matching issues. + Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' + This example illustrates using the Query parameter and JQL syntax to query Jira for matching issues. + .EXAMPLE + Get-JiraIssue -InputObject $oldIssue + This example illustrates how to get an update of an issue from an old result of Get-JiraIssue stored in $oldIssue. + .EXAMPLE + Get-JiraFilter -Id 12345 | Get-JiraIssue + This example retrieves all issues that match the criteria in the saved fiilter with id 12345. .INPUTS - This function can accept PSJira.Issue objects, Strings, or Objects via the pipeline. + This function can accept PSJira.Issue objects, Strings, or Objects via the pipeline. - * If a PSJira.Issue object is passed, this function returns a new reference to the same issue. - * If a String is passed, this function searches for an issue with that issue key or internal ID. - * If an Object is passed, this function invokes its ToString() method and treats it as a String. + * If a PSJira.Issue object is passed, this function returns a new reference to the same issue. + * If a String is passed, this function searches for an issue with that issue key or internal ID. + * If an Object is passed, this function invokes its ToString() method and treats it as a String. .OUTPUTS - This function outputs the PSJira.Issue object retrieved. + This function outputs the PSJira.Issue object retrieved. .NOTES - This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> [CmdletBinding(DefaultParameterSetName = 'ByIssueKey')] param( diff --git a/PSJira/Public/Get-JiraIssueType.ps1 b/PSJira/Public/Get-JiraIssueType.ps1 index 525cf4a5..b4683372 100644 --- a/PSJira/Public/Get-JiraIssueType.ps1 +++ b/PSJira/Public/Get-JiraIssueType.ps1 @@ -1,5 +1,28 @@ function Get-JiraIssueType { + <# + .Synopsis + Returns information about the available issue type in JIRA. + .DESCRIPTION + This function retrieves all the available IssueType on the JIRA server an returns them as PSJira.IssueType. + + This function can restrict the output to a subset of the available IssueTypes if told so. + .EXAMPLE + Get-JiraIssueType + This example returns all the IssueTypes on the JIRA server. + .EXAMPLE + Get-JiraIssueType -IssueType "Bug" + This example returns only the IssueType "Bug". + .EXAMPLE + Get-JiraIssueType -IssueType "Bug","Task","4" + This example return the information about the IssueType named "Bug" and "Task" and with id "4". + .INPUTS + This function accepts Strings via the pipeline. + .OUTPUTS + This function outputs the PSJira.IssueType object retrieved. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> [CmdletBinding()] param( # The Issue Type name or ID to search. diff --git a/PSJira/Public/Get-JiraPriority.ps1 b/PSJira/Public/Get-JiraPriority.ps1 index 9765c512..0bd2095c 100644 --- a/PSJira/Public/Get-JiraPriority.ps1 +++ b/PSJira/Public/Get-JiraPriority.ps1 @@ -1,5 +1,23 @@ function Get-JiraPriority { + <# + .Synopsis + Returns information about the available priorities in JIRA. + .DESCRIPTION + This function retrieves all the available Priorities on the JIRA server an returns them as PSJira.Priority. + + This function can restrict the output to a subset of the available IssueTypes if told so. + .EXAMPLE + Get-JiraPriority + This example returns all the IssueTypes on the JIRA server. + .EXAMPLE + Get-JiraPriority -ID 1 + This example returns only the Priority with ID 1. + .OUTPUTS + This function outputs the PSJira.Priority object retrieved. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> [CmdletBinding()] param( # ID of the priority to get. diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index beaf00ff..2ed2779e 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -62,11 +62,12 @@ function New-JiraIssue [Parameter(Mandatory = $false)] [String] $Parent, - # Set the FixVersion of the issue + # Set the FixVersion of the issue. [Parameter(Mandatory = $false)] [Alias('FixVersions')] [String[]] $FixVersion, + # Any additional fields. [Parameter(Mandatory = $false)] [Hashtable] $Fields, diff --git a/PSJira/Public/Set-JiraIssueLabel.ps1 b/PSJira/Public/Set-JiraIssueLabel.ps1 index 78671bb3..b4a9b9ac 100644 --- a/PSJira/Public/Set-JiraIssueLabel.ps1 +++ b/PSJira/Public/Set-JiraIssueLabel.ps1 @@ -2,31 +2,32 @@ { <# .Synopsis - Modifies labels on an existing JIRA issue + Modifies labels on an existing JIRA issue .DESCRIPTION - This function modifies labels on an existing JIRA issue. There are - four supported operations on labels: - - * Add: appends additional labels to the labels that an issue already has - * Remove: Removes labels from an issue's current labels - * Set: erases the existing labels on the issue and replaces them with - the provided values - * Clear: removes all labels from the issue + This function modifies labels on an existing JIRA issue. There are + four supported operations on labels: + + * Add: appends additional labels to the labels that an issue already has + * Remove: Removes labels from an issue's current labels + * Set: erases the existing labels on the issue and replaces them with + the provided values + * Clear: removes all labels from the issue .EXAMPLE - Set-JiraIssueLabel -Issue TEST-01 -Set 'fixed' - This example replaces all existing labels on issue TEST-01 with one - label, "fixed". + Set-JiraIssueLabel -Issue TEST-01 -Set 'fixed' + This example replaces all existing labels on issue TEST-01 with one + label, "fixed". .EXAMPLE - $jql = 'created >= -7d AND reporter in (joeSmith)' - Get-JiraIssue -Query $jql | Set-JiraIssueLabel -Add 'enhancement' - This issue adds the "enhancement" label to all issues matching the JQL - set in the $jql variable - in this case, all issues created by user - joeSmith in the last 7 days. + Get-JiraIssue -Query 'created >= -7d AND reporter in (joeSmith)' | Set-JiraIssueLabel -Add 'enhancement' + This example adds the "enhancement" label to all issues matching the JQL - in this case, + all issues created by user joeSmith in the last 7 days. + .EXAMPLE + Get-JiraIssue TEST-01 | Set-JiraIssueLabel -Clear + This example removes all labels from the issue TEST-01. .INPUTS - [PSJira.Issue[]] The JIRA issue that should be modified + [PSJira.Issue[]] The JIRA issue that should be modified .OUTPUTS - If the -PassThru parameter is provided, this function will provide a reference - to the JIRA issue modified. Otherwise, this function does not provide output. + If the -PassThru parameter is provided, this function will provide a reference + to the JIRA issue modified. Otherwise, this function does not provide output. #> [CmdletBinding(DefaultParameterSetName = 'ReplaceLabels')] param( From e23072e81bfe8d89a4eabb96915dc4f80c02f9f2 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 14:14:17 +0200 Subject: [PATCH 072/102] Update work to fit new Test schema --- PSJira/Internal/ConvertTo-JiraIssue.ps1 | 96 +++++++++---------- .../ConvertTo-JiraIssueLinkType.Tests.ps1 | 82 ---------------- .../Internal/ConvertTo-JiraIssueLinkType.ps1 | 50 +++++++--- Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 | 72 ++++++++++++++ .../Get-JiraIssueLinkType.Tests.ps1 | 73 +++++--------- 5 files changed, 175 insertions(+), 198 deletions(-) delete mode 100644 PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 create mode 100644 Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 rename {PSJira/Public => Tests}/Get-JiraIssueLinkType.Tests.ps1 (60%) diff --git a/PSJira/Internal/ConvertTo-JiraIssue.ps1 b/PSJira/Internal/ConvertTo-JiraIssue.ps1 index 439d7b66..d3bddad3 100644 --- a/PSJira/Internal/ConvertTo-JiraIssue.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssue.ps1 @@ -30,13 +30,11 @@ function ConvertTo-JiraIssue # Write-Debug "[ConvertTo-JiraIssue] Processing object: '$i'" - if ($i.errorMessages) - { -# Write-Debug "[ConvertTo-JiraIssue] Detected an errorMessages property. This is an error result." + if ($i.errorMessages) { + # Write-Debug "[ConvertTo-JiraIssue] Detected an errorMessages property. This is an error result." - if ($ReturnError) - { -# Write-Debug "[ConvertTo-JiraIssue] Outputting details about error message" + if ($ReturnError) { + # Write-Debug "[ConvertTo-JiraIssue] Outputting details about error message" $props = @{ 'ErrorMessages' = $i.errorMessages; } @@ -46,101 +44,95 @@ function ConvertTo-JiraIssue Write-Output $result } - } else { + } + else { $server = ($InputObject.self -split 'rest')[0] $http = "${server}browse/$($i.key)" -# Write-Debug "[ConvertTo-JiraIssue] Defining standard properties" + # Write-Debug "[ConvertTo-JiraIssue] Defining standard properties" +$global:foo = $i.fields.issuelinks | Out-Default $props = @{ - 'Key' = $i.key; - 'ID' = $i.id; - 'RestUrl' = $i.self; - 'HttpUrl' = $http; - 'Summary' = $i.fields.summary; + 'Key' = $i.key; + 'ID' = $i.id; + 'RestUrl' = $i.self; + 'HttpUrl' = $http; + 'Summary' = $i.fields.summary; 'Description' = $i.fields.description; - 'Status' = $i.fields.status.name; + 'Status' = $i.fields.status.name; } + if ($i.fields.issuelinks) { $props['IssueLinks'] = (ConvertTo-JiraIssueLink $i.fields.issuelinks)} - if ($i.fields.project) - { -# Write-Debug "[ConvertTo-JiraIssue] Obtaining reference to project" + if ($i.fields.project) { + # Write-Debug "[ConvertTo-JiraIssue] Obtaining reference to project" $props.Project = ConvertTo-JiraProject -InputObject $i.fields.project } - foreach ($field in $userFields) - { -# Write-Debug "[ConvertTo-JiraIssue] Checking for user field [$field]" - if ($i.fields.$field) - { -# Write-Debug "[ConvertTo-JiraIssue] Adding user field $field" + foreach ($field in $userFields) { + # Write-Debug "[ConvertTo-JiraIssue] Checking for user field [$field]" + if ($i.fields.$field) { + # Write-Debug "[ConvertTo-JiraIssue] Adding user field $field" $props.$field = ConvertTo-JiraUser -InputObject $i.fields.$field - } elseif ($field -eq 'Assignee') { -# Write-Debug "[ConvertTo-JiraIssue] Adding 'Unassigned' assignee field" + } + elseif ($field -eq 'Assignee') { + # Write-Debug "[ConvertTo-JiraIssue] Adding 'Unassigned' assignee field" $props.Assignee = 'Unassigned' - } else { -# Write-Debug "[ConvertTo-JiraIssue] Object does not appear to contain property [$field]" + } + else { + # Write-Debug "[ConvertTo-JiraIssue] Object does not appear to contain property [$field]" } } - foreach ($field in $dateFields) - { - if ($i.fields.$field) - { -# Write-Debug "[ConvertTo-JiraIssue] Adding date field $field" + foreach ($field in $dateFields) { + if ($i.fields.$field) { + # Write-Debug "[ConvertTo-JiraIssue] Adding date field $field" $props.$field = Get-Date -Date ($i.fields.$field) } } - if ($IncludeDebug) - { -# Write-Debug "[ConvertTo-JiraIssue] Defining debug properties" + if ($IncludeDebug) { + # Write-Debug "[ConvertTo-JiraIssue] Defining debug properties" $props.Fields = $i.fields $props.Expand = $i.expand } # Write-Debug "[ConvertTo-JiraIssue] Adding transitions" [void] $transitions.Clear() - foreach ($t in $i.transitions) - { + foreach ($t in $i.transitions) { [void] $transitions.Add((ConvertTo-JiraTransition -InputObject $t)) } $props.Transition = ($transitions.ToArray()) -# Write-Debug "[ConvertTo-JiraIssue] Adding comments" + # Write-Debug "[ConvertTo-JiraIssue] Adding comments" [void] $comments.Clear() - if ($i.fields.comment) - { - if ($i.fields.comment.comments) - { - foreach ($c in $i.fields.comment.comments) - { + if ($i.fields.comment) { + if ($i.fields.comment.comments) { + foreach ($c in $i.fields.comment.comments) { [void] $comments.Add((ConvertTo-JiraComment -InputObject $c)) } $props.Comment = ($comments.ToArray()) } } -# Write-Debug "[ConvertTo-JiraIssue] Checking for any additional fields" + # Write-Debug "[ConvertTo-JiraIssue] Checking for any additional fields" $extraFields = $i.fields.PSObject.Properties | Where-Object -FilterScript { $_.Name -notin $props.Keys } - foreach ($f in $extraFields) - { + foreach ($f in $extraFields) { $name = $f.Name -# Write-Debug "[ConvertTo-JiraIssue] Adding property [$name] with value [$($f.Value)]" + # Write-Debug "[ConvertTo-JiraIssue] Adding property [$name] with value [$($f.Value)]" $props[$name] = $f.Value } -# Write-Debug "[ConvertTo-JiraIssue] Creating PSObject out of properties" + # Write-Debug "[ConvertTo-JiraIssue] Creating PSObject out of properties" $result = New-Object -TypeName PSObject -Property $props -# Write-Debug "[ConvertTo-JiraIssue] Inserting type name information" + # Write-Debug "[ConvertTo-JiraIssue] Inserting type name information" $result.PSObject.TypeNames.Insert(0, 'PSJira.Issue') -# Write-Debug "[ConvertTo-JiraProject] Inserting custom toString() method" + # Write-Debug "[ConvertTo-JiraProject] Inserting custom toString() method" $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { Write-Output "[$($this.Key)] $($this.Summary)" } -# Write-Debug "[ConvertTo-JiraIssue] Outputting object" + # Write-Debug "[ConvertTo-JiraIssue] Outputting object" Write-Output $result } } diff --git a/PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 deleted file mode 100644 index c8e4359f..00000000 --- a/PSJira/Internal/ConvertTo-JiraIssueLinkType.Tests.ps1 +++ /dev/null @@ -1,82 +0,0 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" - -InModuleScope PSJira { - Describe "ConvertTo-JiraIssueLinkType" { - function defProp($obj, $propName, $propValue) - { - It "Defines the '$propName' property" { - $obj.$propName | Should Be $propValue - } - } - - $sampleJson = @' -{ - "issueLinkTypes": [ - { - "id": "10000", - "name": "Blocks", - "inward": "is blocked by", - "outward": "blocks", - "self": "http://jira.example.com/rest/api/latest/issueLinkType/10000" - }, - { - "id": "10001", - "name": "Cloners", - "inward": "is cloned by", - "outward": "clones", - "self": "http://jira.example.com/rest/api/latest/issueLinkType/10001" - }, - { - "id": "10002", - "name": "Duplicate", - "inward": "is duplicated by", - "outward": "duplicates", - "self": "http://jira.example.com/rest/api/latest/issueLinkType/10002" - }, - { - "id": "10003", - "name": "Relates", - "inward": "relates to", - "outward": "relates to", - "self": "http://jira.example.com/rest/api/latest/issueLinkType/10003" - } - ] -} -'@ - $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson | - Select-Object -ExpandProperty issueLinkTypes - - Context 'Behavior testing' { - $r = ConvertTo-JiraIssueLinkType -InputObject $sampleObject[0] - It "Provides output" { - $r | Should Not BeNullOrEmpty - } - - It "Sets the type name to PSJira.issueLinkType" { - ($r | Get-Member).TypeName | Should Be 'PSJira.issueLinkType' - } - - defProp $r 'Id' '10000' - defProp $r 'Name' 'Blocks' - defProp $r 'InwardText' 'is blocked by' - defProp $r 'OutwardText' 'blocks' - defProp $r 'RestUrl' 'http://jira.example.com/rest/api/latest/issueLinkType/10000' - - It "Provides an array of objects if an array is passed" { - $r2 = ConvertTo-JiraIssueLinkType -InputObject $sampleObject - $r2.Count | Should Be 4 - $r2[0].Id | Should Be '10000' - $r2[1].Id | Should Be '10001' - $r2[2].Id | Should Be '10002' - $r2[3].Id | Should Be '10003' - } - - It "Handles pipeline input" { - $r = $sampleObject | ConvertTo-JiraIssueLinkType - $r.Count | Should Be 4 - } - } - } -} diff --git a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 index 316d97ac..bf316df8 100644 --- a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 @@ -2,25 +2,45 @@ function ConvertTo-JiraIssueLinkType { [CmdletBinding()] param( [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true)] - [PSObject[]] $InputObject + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject, + + [Switch] $ReturnError ) - process - { - foreach ($i in $InputObject) - { - $obj = [PSCustomObject] @{ - PSTypeName = 'PSJira.IssueLinkType' - Id = $i.id; - Name = $i.name; - InwardText = $i.inward; - OutwardText = $i.outward; - RestUrl = $i.self; + process { + foreach ($i in $InputObject) { + if ($i.errorMessages) { + if ($ReturnError) { + $props = @{ + 'ErrorMessages' = $i.errorMessages; + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'PSJira.Error') + + Write-Output $result + } } + else { + $props = @{ + 'ID' = $i.id; + 'Name' = $i.name; + 'InwardText' = $i.inward; + 'OutwardText' = $i.outward; + 'RestUrl' = $i.self; + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'PSJira.IssueLinkType') - Write-Output $obj + Write-Output $result + } } } + + end + { + } } diff --git a/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 b/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 new file mode 100644 index 00000000..d135002a --- /dev/null +++ b/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 @@ -0,0 +1,72 @@ +. $PSScriptRoot\Shared.ps1 +InModuleScope PSJira { + Describe "ConvertTo-JiraIssueLinkType" { + . $PSScriptRoot\Shared.ps1 + + $jiraServer = 'http://jiraserver.example.com' + + $sampleJson = @' +{ + "issueLinkTypes": [ + { + "id": "10000", + "name": "Blocks", + "inward": "is blocked by", + "outward": "blocks", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10000" + }, + { + "id": "10001", + "name": "Cloners", + "inward": "is cloned by", + "outward": "clones", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10001" + }, + { + "id": "10002", + "name": "Duplicate", + "inward": "is duplicated by", + "outward": "duplicates", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10002" + }, + { + "id": "10003", + "name": "Relates", + "inward": "relates to", + "outward": "relates to", + "self": "http://jira.example.com/rest/api/latest/issueLinkType/10003" + } + ] +} +'@ + + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson | Select-Object -ExpandProperty issueLinkTypes + + $r = ConvertTo-JiraIssueLinkType -InputObject $sampleObject[0] + It "Creates a PSObject out of JSON input" { + $r | Should Not BeNullOrEmpty + } + + checkPsType $r 'PSJira.IssueLinkType' + + defProp $r 'Id' '10000' + defProp $r 'Name' 'Blocks' + defProp $r 'InwardText' 'is blocked by' + defProp $r 'OutwardText' 'blocks' + defProp $r 'RestUrl' 'http://jira.example.com/rest/api/latest/issueLinkType/10000' + + It "Provides an array of objects if an array is passed" { + $r2 = ConvertTo-JiraIssueLinkType -InputObject $sampleObject + $r2.Count | Should Be 4 + $r2[0].Id | Should Be '10000' + $r2[1].Id | Should Be '10001' + $r2[2].Id | Should Be '10002' + $r2[3].Id | Should Be '10003' + } + + It "Handles pipeline input" { + $r = $sampleObject | ConvertTo-JiraIssueLinkType + $r.Count | Should Be 4 + } + } +} diff --git a/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 b/Tests/Get-JiraIssueLinkType.Tests.ps1 similarity index 60% rename from PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 rename to Tests/Get-JiraIssueLinkType.Tests.ps1 index b9631345..a3ec33b3 100644 --- a/PSJira/Public/Get-JiraIssueLinkType.Tests.ps1 +++ b/Tests/Get-JiraIssueLinkType.Tests.ps1 @@ -1,51 +1,37 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { - $ShowMockData = $false - $ShowDebugText = $false + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 - Describe 'Get-JiraIssueLinkType' { - Mock Get-JiraConfigServer { 'https://jira.example.com' } + $jiraServer = 'http://jiraserver.example.com' - if ($ShowDebugText) - { - Mock 'Write-Debug' { - Write-Host "[DEBUG] $Message" -ForegroundColor Yellow - } - } - - function ShowMockInfo($functionName, [String[]] $params) { - if ($ShowMockData) - { - Write-Host " Mocked $functionName" -ForegroundColor Cyan - foreach ($p in $params) { - Write-Host " [$p] $(Get-Variable -Name $p -ValueOnly)" -ForegroundColor Cyan - } - } + Describe 'Get-JiraIssueLinkType' { + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer } Context "Sanity checking" { $command = Get-Command -Name Get-JiraIssueLinkType - function defParam($name) - { - It "Has a -$name parameter" { - $command.Parameters.Item($name) | Should Not BeNullOrEmpty - } - } - - defParam 'LinkType' - defParam 'Credential' + defParam $command 'LinkType' + defParam $command 'Credential' } - $filterAll = {$Method -eq 'Get' -and $Uri -ceq 'https://jira.example.com/rest/api/latest/issueLinkType'} - $filterOne = {$Method -eq 'Get' -and $Uri -ceq 'https://jira.example.com/rest/api/latest/issueLinkType/10000'} + $filterAll = {$Method -eq 'Get' -and $Uri -ceq "$jiraServer/rest/api/latest/issueLinkType"} + $filterOne = {$Method -eq 'Get' -and $Uri -ceq "$jiraServer/rest/api/latest/issueLinkType/10000"} + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } Mock Invoke-JiraMethod -ParameterFilter $filterAll { - ShowMockInfo 'Invoke-JiraMethod' 'Method','Uri' + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' [PSCustomObject] @{ issueLinkTypes = @( # We don't care what data actually comes back here @@ -55,7 +41,7 @@ InModuleScope PSJira { } Mock Invoke-JiraMethod -ParameterFilter $filterOne { - ShowMockInfo 'Invoke-JiraMethod' 'Method','Uri' + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' [PSCustomObject] @{ issueLinkTypes = @( 'bar' @@ -63,11 +49,6 @@ InModuleScope PSJira { } } - Mock Invoke-JiraMethod { - ShowMockInfo 'Invoke-JiraMethod' 'Method','Uri' - throw "Unhandled call to Invoke-JiraMethod" - } - Context "Behavior testing - returning all link types" { Mock ConvertTo-JiraIssueLinkType { @@ -76,7 +57,7 @@ InModuleScope PSJira { # We also don't care what comes out of here - this function has its own tests [PSCustomObject] @{ PSTypeName = 'PSJira.IssueLinkType' - foo = 'bar' + foo = 'bar' } } @@ -93,12 +74,6 @@ InModuleScope PSJira { It 'Uses the helper method ConvertTo-JiraIssueLinkType to process output' { Assert-MockCalled -CommandName ConvertTo-JiraIssueLinkType -ParameterFilter {$InputObject -contains 'foo'} -Exactly -Times 1 -Scope Context } - - It 'Outputs PSJira.IssueLinkType objects' { - $output | Should Not BeNullOrEmpty - ($output | Get-Member).TypeName | Should Be 'PSJira.IssueLinkType' - $output.foo | Should Be 'bar' - } } Context "Behavior testing - returning one link type" { @@ -108,8 +83,8 @@ InModuleScope PSJira { # We also don't care what comes out of here - this function has its own tests [PSCustomObject] @{ PSTypeName = 'PSJira.IssueLinkType' - Name = 'myLink' - ID = 5 + Name = 'myLink' + ID = 5 } } From ef52391353c212f2ced97d2968c3dec211730dc7 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 14:44:38 +0200 Subject: [PATCH 073/102] implement Get-JiraIssueLink --- PSJira/Public/Get-JiraIssueLink.ps1 | 81 +++++++++++++++++++++++++++++ Tests/Get-JiraIssueLink.Tests.ps1 | 78 +++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 PSJira/Public/Get-JiraIssueLink.ps1 create mode 100644 Tests/Get-JiraIssueLink.Tests.ps1 diff --git a/PSJira/Public/Get-JiraIssueLink.ps1 b/PSJira/Public/Get-JiraIssueLink.ps1 new file mode 100644 index 00000000..f83d2fac --- /dev/null +++ b/PSJira/Public/Get-JiraIssueLink.ps1 @@ -0,0 +1,81 @@ +function Get-JiraIssueLink { + <# + .Synopsis + Returns a specific issueLink from Jira + .DESCRIPTION + This function returns information regarding a specified issueLink from Jira. + .EXAMPLE + Get-JiraIssueLink 10000 + Returns information about the IssueLink with ID 10000 + .EXAMPLE + Get-JiraIssueLink -IssueLink 10000 + Returns information about the IssueLink with ID 10000 + .EXAMPLE + (Get-JiraIssue TEST-01).issuelinks | Get-JiraIssueLink + Returns the information about all IssueLinks in issue TEST-01 + .INPUTS + [Int[]] issueLink ID + [PSCredential] Credentials to use to connect to Jira + .OUTPUTS + [PSJira.IssueLink] + #> + [CmdletBinding()] + param( + # The IssueLink ID to search + # + # Accepts input from pipeline when the object is of type PSJira.IssueLink + [Parameter( + Position = 0, + Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true + )] + [Int[]] $Id, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin { + Write-Debug "[Get-JiraIssueLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + $uri = "$server/rest/api/2/issueLink/{0}" + } + + process { + # Validate input object from Pipeline + if (($_) -and ($_.PSObject.TypeNames[0] -ne "PSJira.IssueLink")) { + $message = "Wrong object type provided for IssueLink." + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + foreach ($ilink in $Id) { + Write-Debug "[Get-JiraIssueLink] Processing project [$ilink]" + $thisUri = $uri -f $ilink + + Write-Debug "[Get-JiraIssueLink] Preparing for blastoff!" + + $result = Invoke-JiraMethod -Method Get -URI $thisUri -Credential $Credential + if ($result) { + Write-Debug "[Get-JiraIssueLink] Converting to object" + $obj = ConvertTo-JiraIssueLink -InputObject $result + + Write-Debug "[Get-JiraIssueLink] Outputting result" + Write-Output $obj + } + else { + Write-Debug "[Get-JiraIssueLink] No results were returned from Jira" + Write-Debug "[Get-JiraIssueLink] No results were returned from Jira for project [$ilink]" + } + } + } + + end { + Write-Debug "[Get-JiraIssueLink] Complete" + } +} + + diff --git a/Tests/Get-JiraIssueLink.Tests.ps1 b/Tests/Get-JiraIssueLink.Tests.ps1 new file mode 100644 index 00000000..6f4f2055 --- /dev/null +++ b/Tests/Get-JiraIssueLink.Tests.ps1 @@ -0,0 +1,78 @@ +. $PSScriptRoot\Shared.ps1 + +InModuleScope PSJira { + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 + + $jiraServer = 'http://jiraserver.example.com' + + $issueLinkId = 1234 + + # We don't care about anything except for the id + $resultsJson = @" +{ + "id": "$issueLinkId", + "self": "", + "type": {}, + "inwardIssue": {}, + "outwardIssue": {} +} +"@ + + Describe "Get-JiraIssueLink" { + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/2/issueLink/1234"} { + ConvertFrom-Json2 $resultsJson + } + + Mock Get-JiraIssue -ModuleName PSJira -ParameterFilter {$Key -eq "TEST-01"} { + # We don't care about the content of any field except for the id + $obj = [PSCustomObject]@{ + "id" = $issueLinkId + "type" = "foo" + "inwardIssue" = "bar" + } + $obj.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + return [PSCustomObject]@{ + issueLinks = @( + $obj + ) + } + } + + ############# + # Tests + ############# + + It "Returns details about specific issuelink" { + $result = Get-JiraIssueLink -Id $issueLinkId + $result | Should Not BeNullOrEmpty + @($result).Count | Should Be 1 + } + + It "Provides the key of the project" { + $result = Get-JiraIssueLink -Id $issueLinkId + $result.Id | Should Be $issueLinkId + } + + It "Accepts input from pipeline" { + $result = (Get-JiraIssue -Key TEST-01).issuelinks | Get-JiraIssueLink + $result.Id | Should Be $issueLinkId + } + + It 'Fails if input from the pipeline is of the wrong type' { + { [PSCustomObject]@{id = $issueLinkId} | Get-JiraIssueLink } | Should Throw + } + } +} From 9759f13c3f357bef0acdcdb9f78a43a0e2a61704 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 14:45:10 +0200 Subject: [PATCH 074/102] remove debug info --- PSJira/Internal/ConvertTo-JiraIssue.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/PSJira/Internal/ConvertTo-JiraIssue.ps1 b/PSJira/Internal/ConvertTo-JiraIssue.ps1 index d3bddad3..ce0231b4 100644 --- a/PSJira/Internal/ConvertTo-JiraIssue.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssue.ps1 @@ -50,7 +50,6 @@ function ConvertTo-JiraIssue $http = "${server}browse/$($i.key)" # Write-Debug "[ConvertTo-JiraIssue] Defining standard properties" -$global:foo = $i.fields.issuelinks | Out-Default $props = @{ 'Key' = $i.key; 'ID' = $i.id; From 3ad7b88fc1d405c718e8a6567f6addb239ab6823 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 14:59:41 +0200 Subject: [PATCH 075/102] Implement conversion to IssueLink objects --- PSJira/Internal/ConvertTo-JiraIssueLink.ps1 | 45 +++++++++++++++++++ Tests/ConvertTo-JiraIssueLink.Tests.ps1 | 50 +++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 PSJira/Internal/ConvertTo-JiraIssueLink.ps1 create mode 100644 Tests/ConvertTo-JiraIssueLink.Tests.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 new file mode 100644 index 00000000..e92be588 --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 @@ -0,0 +1,45 @@ +function ConvertTo-JiraIssueLink { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject, + + [Switch] $ReturnError + ) + + process { + foreach ($i in $InputObject) { + if ($i.errorMessages) { + if ($ReturnError) { + $props = @{ + 'ErrorMessages' = $i.errorMessages; + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'PSJira.Error') + + Write-Output $result + } + } + else { + $props = @{ + 'ID' = $i.id + 'Type' = (ConvertTo-JiraIssueLinkType $i.type) + } + if ($i.inwardIssue) { $props['InwardIssue'] = (ConvertTo-JiraIssue $i.inwardIssue) } + if ($i.outwardIssue) { $props['OutwardIssue'] = (ConvertTo-JiraIssue $i.outwardIssue) } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + + Write-Output $result + } + } + } + + end + { + } +} diff --git a/Tests/ConvertTo-JiraIssueLink.Tests.ps1 b/Tests/ConvertTo-JiraIssueLink.Tests.ps1 new file mode 100644 index 00000000..0e96a94c --- /dev/null +++ b/Tests/ConvertTo-JiraIssueLink.Tests.ps1 @@ -0,0 +1,50 @@ +. $PSScriptRoot\Shared.ps1 +InModuleScope PSJira { + Describe "ConvertTo-JiraIssueLink" { + . $PSScriptRoot\Shared.ps1 + + $jiraServer = 'http://jiraserver.example.com' + + $issueLinkId = 41313 + $issueKeyInward = "TEST-01" + $issueKeyOutward = "TEST-10" + $linkTypeName = "Composition" + + $sampleJson = @" +{ + "id": "$issueLinkId", + "type": { + "id": "10500", + "name": "$linkTypeName", + "inward": "is part of", + "outward": "composes" + }, + "inwardIssue": { + "key": "$issueKeyInward" + }, + "outwardIssue": { + "key": "$issueKeyOutward" + } +} +"@ + + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson + + $r = ConvertTo-JiraIssueLink -InputObject $sampleObject + It "Creates a PSObject out of JSON input" { + $r | Should Not BeNullOrEmpty + } + + checkPsType $r 'PSJira.IssueLink' + + defProp $r 'Id' $issueLinkId + defProp $r 'Type' "@{OutwardText=composes; InwardText=is part of; Name=Composition; ID=10500; RestUrl=}" + defProp $r 'InwardIssue' "[$issueKeyInward] " + defProp $r 'OutwardIssue' "[$issueKeyOutward] " + + It "Handles pipeline input" { + $r = $sampleObject | ConvertTo-JiraIssueLink + @($r).Count | Should Be 1 + } + } +} From 12c03e17de63ca76da4989c43f5c7594089de54a Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 20:38:39 +0200 Subject: [PATCH 076/102] Implement Add-JiraIssueLink --- PSJira/Public/Add-JiraIssueLink.ps1 | 98 +++++++++++++++++++++++++++++ Tests/Add-JiraIssueLink.Tests.ps1 | 71 +++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 PSJira/Public/Add-JiraIssueLink.ps1 create mode 100644 Tests/Add-JiraIssueLink.Tests.ps1 diff --git a/PSJira/Public/Add-JiraIssueLink.ps1 b/PSJira/Public/Add-JiraIssueLink.ps1 new file mode 100644 index 00000000..8cb142fe --- /dev/null +++ b/PSJira/Public/Add-JiraIssueLink.ps1 @@ -0,0 +1,98 @@ +function Add-JiraIssueLink { + <# + .Synopsis + Adds a link between two Issues on Jira + .DESCRIPTION + Creates a new link of the specified type between two Issue. + .EXAMPLE + $link = [PSCustomObject]@{ + outwardIssue = [PSCustomObject]@{key = "TEST-10"} + type = [PSCustomObject]@{name = "Composition"} + } + Add-JiraIssueLink -Issue TEST-01 -IssueLink $link + Creates a link "is part of" between TEST-01 and TEST-10 + .INPUTS + [PSJira.Issue[]] The JIRA issue that should be modified + [PSJira.Issue[]] The JIRA issue that should be modified + #> + [CmdletBinding()] + param( + # Issue key or PSJira.Issue object returned from Get-JiraIssue + [Parameter( + Position = 0, + Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('Key')] + [Object[]] $Issue, + + # Issue Link to be created. + [Parameter(Mandatory = $true)] + [Object[]] $IssueLink, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential<#, + + [Switch] $PassThru#> + ) + + begin { + Write-Debug "[Add-JiraIssueLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + $issueLinkURL = "$($server)/rest/api/latest/issueLink" + } + + process { + # Validate IssueLink object + $objectProperties = $IssueLink | Get-Member -MemberType *Property + if (-not(($objectProperties.Name -contains "type") -and (($objectProperties.Name -contains "outwardIssue") -or ($objectProperties.Name -contains "inwardIssue")))) { + $message = "The IssueLink provided does not contain the information needed." + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + # Validate input object from Pipeline + if (($_) -and ($_.PSObject.TypeNames[0] -ne "PSJira.Issue")) { + $message = "Wrong object type provided for Issue. Only PSJira.Issue is accepted" + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + foreach ($i in $Issue) { + Write-Debug "[Add-JiraIssueLink] Obtaining reference to issue" + $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential + + foreach ($link in $IssueLink) { + if ($link.inwardIssue) { + $inwardIssue = [PSCustomObject]@{key = $link.inwardIssue.key} + } + else { + $inwardIssue = [PSCustomObject]@{key = $issueObj.key} + } + + if ($link.outwardIssue) { + $outwardIssue = [PSCustomObject]@{key = $link.outwardIssue.key} + } + else { + $outwardIssue = [PSCustomObject]@{key = $issueObj.key} + } + + $body = [PSCustomObject]@{ + type = [PSCustomObject]@{name = $link.type.name} + inwardIssue = $inwardIssue + outwardIssue = $outwardIssue + } + $json = ConvertTo-Json $body + + $null = Invoke-JiraMethod -Method POST -URI $issueLinkURL -Body $json -Credential $Credential + } + } + } + + end { + Write-Debug "[Add-JiraIssueLink] Complete" + } +} diff --git a/Tests/Add-JiraIssueLink.Tests.ps1 b/Tests/Add-JiraIssueLink.Tests.ps1 new file mode 100644 index 00000000..48ab9ed8 --- /dev/null +++ b/Tests/Add-JiraIssueLink.Tests.ps1 @@ -0,0 +1,71 @@ +. $PSScriptRoot\Shared.ps1 + +InModuleScope PSJira { + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 + + $jiraServer = 'http://jiraserver.example.com' + + $issueKey = "TEST-01" + $issueLink = [PSCustomObject]@{ + outwardIssue = [PSCustomObject]@{key = "TEST-10"} + type = [PSCustomObject]@{name = "Composition"} + } + + + Describe 'Add-JiraIssueLink' { + + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue -ParameterFilter { $Key -eq $issueKey } { + [PSCustomObject]@{ + Key = $issueKey; + } + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + + Mock Invoke-JiraMethod -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issueLink"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + return $true + } + + ############# + # Tests + ############# + + Context "Sanity checking" { + $command = Get-Command -Name Add-JiraIssueLink + + defParam $command 'Issue' + defParam $command 'IssueLink' + defParam $command 'Credential' + } + + Context "Functionality" { + + It 'Adds a new IssueLink' { + { Add-JiraIssueLink -Issue $issueKey -IssueLink $issueLink } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It 'Validates the IssueType provided' { + $issueLink = [PSCustomObject]@{ type = "foo" } + { Add-JiraIssueLink -Issue $issueKey -IssueLink $issueLink } | Should Throw + } + + It 'Validates pipeline input object' { + { "foo" | Add-JiraIssueLink -IssueLink $issueLink } | Should Throw + } + } + } +} From 96005cb836277845c9ffb07745bec3abf6dc69b7 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 20:43:17 +0200 Subject: [PATCH 077/102] Add Comment parameter to Add-JiraIssueLink --- PSJira/Public/Add-JiraIssueLink.ps1 | 4 ++++ Tests/Add-JiraIssueLink.Tests.ps1 | 1 + 2 files changed, 5 insertions(+) diff --git a/PSJira/Public/Add-JiraIssueLink.ps1 b/PSJira/Public/Add-JiraIssueLink.ps1 index 8cb142fe..ce06b8bb 100644 --- a/PSJira/Public/Add-JiraIssueLink.ps1 +++ b/PSJira/Public/Add-JiraIssueLink.ps1 @@ -31,6 +31,9 @@ function Add-JiraIssueLink { [Parameter(Mandatory = $true)] [Object[]] $IssueLink, + # Write a comment to the issue + [String] $Comment, + # Credentials to use to connect to Jira [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential<#, @@ -85,6 +88,7 @@ function Add-JiraIssueLink { inwardIssue = $inwardIssue outwardIssue = $outwardIssue } + if ($Comment) {$body["comment"] = [PSCustomObject]@{body = $Comment}} $json = ConvertTo-Json $body $null = Invoke-JiraMethod -Method POST -URI $issueLinkURL -Body $json -Credential $Credential diff --git a/Tests/Add-JiraIssueLink.Tests.ps1 b/Tests/Add-JiraIssueLink.Tests.ps1 index 48ab9ed8..ad1f0352 100644 --- a/Tests/Add-JiraIssueLink.Tests.ps1 +++ b/Tests/Add-JiraIssueLink.Tests.ps1 @@ -47,6 +47,7 @@ InModuleScope PSJira { defParam $command 'Issue' defParam $command 'IssueLink' + defParam $command 'Comment' defParam $command 'Credential' } From 2c0a63122c0e521d1df84aaaf0f70202c6502ca7 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 20:48:19 +0200 Subject: [PATCH 078/102] Fix input description --- PSJira/Public/Add-JiraIssueLink.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PSJira/Public/Add-JiraIssueLink.ps1 b/PSJira/Public/Add-JiraIssueLink.ps1 index ce06b8bb..e3866455 100644 --- a/PSJira/Public/Add-JiraIssueLink.ps1 +++ b/PSJira/Public/Add-JiraIssueLink.ps1 @@ -12,8 +12,8 @@ function Add-JiraIssueLink { Add-JiraIssueLink -Issue TEST-01 -IssueLink $link Creates a link "is part of" between TEST-01 and TEST-10 .INPUTS - [PSJira.Issue[]] The JIRA issue that should be modified - [PSJira.Issue[]] The JIRA issue that should be modified + [PSJira.Issue[]] The JIRA issue that should be linked + [PSJira.IssueLink[]] The JIRA issue link that should be used #> [CmdletBinding()] param( From 184fd63f53b86ae3a9baa42bb93084b23601ab8e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 12 Jun 2017 21:27:44 +0200 Subject: [PATCH 079/102] Implement Remove-JiraIssueLink --- PSJira/Public/Remove-JiraIssueLink.ps1 | 79 +++++++++++++++++++ Tests/Remove-JiraIssueLink.Tests.ps1 | 102 +++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 PSJira/Public/Remove-JiraIssueLink.ps1 create mode 100644 Tests/Remove-JiraIssueLink.Tests.ps1 diff --git a/PSJira/Public/Remove-JiraIssueLink.ps1 b/PSJira/Public/Remove-JiraIssueLink.ps1 new file mode 100644 index 00000000..fd6aff55 --- /dev/null +++ b/PSJira/Public/Remove-JiraIssueLink.ps1 @@ -0,0 +1,79 @@ +function Remove-JiraIssueLink { + <# + .Synopsis + Removes a issue link from a JIRA issue + .DESCRIPTION + This function removes a issue link from a JIRA issue. + .EXAMPLE + Remove-JiraIssueLink 1234,2345 + Removes two issue links with id 1234 and 2345 + .EXAMPLE + Get-JiraIssue -Query "project = Project1 AND label = lingering" | Remove-JiraIssueLink + Removes all issue links for all issues in project Project1 and that have a label "lingering" + .INPUTS + [PSJira.IssueLink[]] The JIRA issue link which to delete + .OUTPUTS + This function returns no output. + #> + [CmdletBinding( + SupportsShouldProcess = $true, + ConfirmImpact = 'Medium' + )] + param( + # IssueLink to delete + [Parameter( + Position = 0, + Mandatory = $true, + ValueFromPipeline = $true + )] + [Object[]] $IssueLink, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [PSCredential] $Credential + ) + + Begin { + Write-Debug "[Remove-JiraIssueLink] Reading Jira server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + $restUrl = "$server/rest/api/latest/issueLink/{0}" + } + + Process { + + # As we are not able to use proper type casting in the parameters, this is a workaround + # to extract the data from a PSJira.Issue object + if (($_) -and ($_.PSObject.TypeNames[0] -eq "PSJira.Issue")) { + $IssueLink = $_.issueLinks + } + + # Validate IssueLink object + $objectProperties = $IssueLink | Get-Member -MemberType *Property + if (-not($objectProperties.Name -contains "id")) { + $message = "The IssueLink provided does not contain the information needed. $($objectProperties | Out-String)" + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + # Validate input object from Pipeline + if (($_) -and ($_.PSObject.TypeNames[0] -notin @("PSJira.IssueLink", "PSJira.Issue"))) { + $message = "Wrong object type provided for Issue. Only PSJira.IssueLink is accepted" + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + foreach ($link in $IssueLink) { + Write-Debug "[Remove-JiraIssueLink] Processing issue key [$k]" + $thisUrl = $restUrl -f $link.id + if ($PSCmdlet.ShouldProcess($link.id, "Remove IssueLink")) { + Write-Debug "[Remove-JiraIssueLink] Preparing for blastoff!" + Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential + } + } + } + + End { + Write-Debug "[Remove-JiraIssueLink] Complete" + } +} diff --git a/Tests/Remove-JiraIssueLink.Tests.ps1 b/Tests/Remove-JiraIssueLink.Tests.ps1 new file mode 100644 index 00000000..dab842ff --- /dev/null +++ b/Tests/Remove-JiraIssueLink.Tests.ps1 @@ -0,0 +1,102 @@ +. $PSScriptRoot\Shared.ps1 + +InModuleScope PSJira { + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 + + $jiraServer = 'http://jiraserver.example.com' + + $issueLinkId = 1234 + + # We don't care about anything except for the id + $resultsJson = @" +{ + "id": "$issueLinkId", + "self": "", + "type": {}, + "inwardIssue": {}, + "outwardIssue": {} +} +"@ + + Describe "Remove-JiraIssueLink" { + $showMockData = $true + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Delete' -and $URI -eq "$jiraServer/rest/api/latest/issueLink/1234"} { + return $null + } + + Mock Get-JiraIssue -ModuleName PSJira -ParameterFilter {$Key -eq "TEST-01"} { + # We don't care about the content of any field except for the id of the issuelinks + $obj = [PSCustomObject]@{ + "id" = $issueLinkId + "type" = "foo" + "inwardIssue" = "bar" + } + $obj.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + $issue = [PSCustomObject]@{ + issueLinks = @( + $obj + ) + } + $issue.PSObject.TypeNames.Insert(0, 'PSJira.Issue') + return $issue + } + + Mock Get-JiraIssueLink -ModuleName PSJira { + $obj = [PSCustomObject]@{ + "id" = $issueLinkId + "type" = "foo" + "inwardIssue" = "bar" + } + $obj.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + return $obj + } + + ############# + # Tests + ############# + + Context "Sanity checking" { + $command = Get-Command -Name Remove-JiraIssueLink + + defParam $command 'IssueLink' + defParam $command 'Credential' + } + + Context "Functionality" { + + + It "Accepts generic object with the correct properties" { + $issueLink = [PSCustomObject]@{ id = $issueLinkId } + { Remove-JiraIssueLink -IssueLink $issueLink } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Accepts a PSJira.Issue object over the pipeline" { + { Get-JiraIssue -Key TEST-01 | Remove-JiraIssueLink } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Accepts a PSJira.IssueType over the pipeline" { + { Get-JiraIssueLink -Id 1234 | Remove-JiraIssueLink } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Validates pipeline input" { + { @{id = 1} | Remove-JiraIssueLink } | Should Throw + } + } + } +} From d7bb543e5b5d8bfbdb41190e4287d7edcbb06ba2 Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Mon, 12 Jun 2017 13:46:36 -0700 Subject: [PATCH 080/102] Many suggestions from @lipkau. --- PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 | 2 +- PSJira/Public/Add-JiraIssueWorklog.ps1 | 68 +++++++++---------- Tests/Add-JiraIssueWorklog.Tests.ps1 | 22 +++--- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 b/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 index 9ccb54a7..1fa28941 100644 --- a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 +++ b/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 @@ -1,4 +1,4 @@ -function ConvertTo-JiraWorklogitem +function ConvertTo-JiraWorklogItem { [CmdletBinding()] param( diff --git a/PSJira/Public/Add-JiraIssueWorklog.ps1 b/PSJira/Public/Add-JiraIssueWorklog.ps1 index f7e03b67..b8c8eab3 100644 --- a/PSJira/Public/Add-JiraIssueWorklog.ps1 +++ b/PSJira/Public/Add-JiraIssueWorklog.ps1 @@ -27,12 +27,12 @@ function Add-JiraIssueWorklog #> [CmdletBinding()] param( - # Comment that should be added to JIRA + # Worklog item that should be added to JIRA [Parameter(Mandatory = $true, Position = 0)] [String] $Comment, - # Issue that should be commented upon + # Issue to receive the new worklog item [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, @@ -40,19 +40,19 @@ function Add-JiraIssueWorklog [Alias('Key')] [Object] $Issue, - # Time spent to be logged, in seconds + # Time spent to be logged [Parameter(Mandatory = $true, Position = 2, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] - [Int] $TimeSpent, + [TimeSpan] $TimeSpent, # Date/time started to be logged [Parameter(Mandatory = $true, Position = 3, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] - [String] $DateStarted, + [DateTime] $DateStarted, # Visibility of the comment - should it be publicly visible, viewable to only developers, or only administrators? [ValidateSet('All Users','Developers','Administrators')] @@ -71,41 +71,41 @@ function Add-JiraIssueWorklog process { -# Write-Debug "[Add-JiraIssueWorklog] Checking Issue parameter" -# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') -# { -# Write-Debug "[Add-JiraIssueWorklog] Issue parameter is a PSJira.Issue object" -# $issueObj = $Issue -# } else { -# $issueKey = $Issue.ToString() -# Write-Debug "[Add-JiraIssueWorklog] Issue key is assumed to be [$issueKey] via ToString()" -# Write-Verbose "Searching for issue [$issueKey]" -# try -# { -# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential -# } catch { -# $err = $_ -# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' -# throw $err -# } -# } -# -# if (-not $issueObj) -# { -# Write-Debug "[Add-JiraIssueWorklog] No Jira issues were found for parameter [$Issue]. An exception will be thrown." -# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" -# } - - Write-Debug "[Add-JiraIssueWorklog] Obtaining a reference to Jira issue [$Issue]" - $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential + Write-Debug "[Add-JiraIssueWorklog] Checking Issue parameter" + if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') + { + Write-Debug "[Add-JiraIssueWorklog] Issue parameter is a PSJira.Issue object" + $issueObj = $Issue + } else { + $issueKey = $Issue.ToString() + Write-Debug "[Add-JiraIssueWorklog] Issue key is assumed to be [$issueKey] via ToString()" + Write-Verbose "Searching for issue [$issueKey]" + try + { + $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential + } catch { + $err = $_ + Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' + throw $err + } + } + + if (-not $issueObj) + { + Write-Debug "[Add-JiraIssueWorklog] No Jira issues were found for parameter [$Issue]. An exception will be thrown." + throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" + } + + #Write-Debug "[Add-JiraIssueWorklog] Obtaining a reference to Jira issue [$Issue]" + #$issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential $url = "$($issueObj.RestURL)/worklog" Write-Debug "[Add-JiraIssueWorklog] Creating request body from comment" $props = @{ 'comment' = $Comment; - 'started' = $DateStarted; - 'timeSpent' = $TimeSpent + 'started' = $DateStarted.ToString(); + 'timeSpent' = $TimeSpent.TotalSeconds.ToString(); } diff --git a/Tests/Add-JiraIssueWorklog.Tests.ps1 b/Tests/Add-JiraIssueWorklog.Tests.ps1 index 2356a155..3e59bee4 100644 --- a/Tests/Add-JiraIssueWorklog.Tests.ps1 +++ b/Tests/Add-JiraIssueWorklog.Tests.ps1 @@ -58,11 +58,13 @@ InModuleScope PSJira { } Mock Get-JiraIssue -ModuleName PSJira { - [PSCustomObject] @{ + $result = [PSCustomObject] @{ ID = $issueID; Key = $issueKey; RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; } + $result.PSObject.TypeNames.Insert(0, 'PSJira.Issue') + Write-Output $result } Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/worklog"} { @@ -90,9 +92,10 @@ InModuleScope PSJira { # Tests ############# - It "Adds a comment to an issue in JIRA" { + It "Adds a worklog item to an issue in JIRA" { $commentResult = Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent 3600 -DateStarted "2018-01-01" - $commentResult | Should Not BeNullOrEmpty + # BeNullOrEmpty test doesn't work on the PSJira.WorklogItem passed to it, so let's test a required property instead + $commentResult.ID | Should Not BeNullOrEmpty # Get-JiraIssue should be used to identify the issue parameter Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It @@ -102,18 +105,13 @@ InModuleScope PSJira { } It "Accepts pipeline input from Get-JiraIssue" { - $commentResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWorklog -Comment 'This is a test comment from Pester, using the pipeline!' -TimeSpent "3600" -DateStarted "2018-01-01" - $commentResult | Should Not BeNullOrEmpty + $commentResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWorklog -Comment 'This is a test worklog item from Pester, using the pipeline!' -TimeSpent "3600" -DateStarted "2018-01-01" + $commentResult.ID | Should Not BeNullOrEmpty - # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWorklog (to identify the InputObject parameter) - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It + # Get-JiraIssue should be called once here to fetch the initial test issue + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It } - - It "Outputs the comment as a PSJira.Worklogitem object" { - $commentResult = Add-JiraIssueWorklog -Comment 'This is a test comment from Pester.' -Issue $issueKey -TimeSpent "3600" -DateStarted "2018-01-01" - (Get-Member -InputObject $commentResult).TypeName | Should Be 'PSJira.Worklogitem' - } } } From 434dcef811959f47068602557b27f39ce5dd37ed Mon Sep 17 00:00:00 2001 From: Josh Knorr Date: Mon, 12 Jun 2017 14:21:28 -0700 Subject: [PATCH 081/102] Fixed problem with toString method for ConvertTo-WorklogItem --- PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 | 4 ++-- Tests/Add-JiraIssueWorklog.Tests.ps1 | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 b/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 index 1fa28941..62d45521 100644 --- a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 +++ b/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 @@ -65,7 +65,7 @@ function ConvertTo-JiraWorklogItem if ($i.timeSpentSeconds) { $props.TimeSpentSeconds = $i.timeSpentSeconds - } + } # Write-Debug "[ConvertTo-JiraWorklogitem] Creating PSObject out of properties" $result = New-Object -TypeName PSObject -Property $props @@ -75,7 +75,7 @@ function ConvertTo-JiraWorklogItem # Write-Debug "[ConvertTo-JiraWorklogitem] Inserting custom toString() method" $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { - Write-Output "$($this.Body)" + Write-Output "$($this.Id)" } # Write-Debug "[ConvertTo-JiraWorklogitem] Outputting object" diff --git a/Tests/Add-JiraIssueWorklog.Tests.ps1 b/Tests/Add-JiraIssueWorklog.Tests.ps1 index 3e59bee4..483324d9 100644 --- a/Tests/Add-JiraIssueWorklog.Tests.ps1 +++ b/Tests/Add-JiraIssueWorklog.Tests.ps1 @@ -94,8 +94,7 @@ InModuleScope PSJira { It "Adds a worklog item to an issue in JIRA" { $commentResult = Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent 3600 -DateStarted "2018-01-01" - # BeNullOrEmpty test doesn't work on the PSJira.WorklogItem passed to it, so let's test a required property instead - $commentResult.ID | Should Not BeNullOrEmpty + $commentResult | Should Not BeNullOrEmpty # Get-JiraIssue should be used to identify the issue parameter Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It @@ -106,7 +105,7 @@ InModuleScope PSJira { It "Accepts pipeline input from Get-JiraIssue" { $commentResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWorklog -Comment 'This is a test worklog item from Pester, using the pipeline!' -TimeSpent "3600" -DateStarted "2018-01-01" - $commentResult.ID | Should Not BeNullOrEmpty + $commentResult | Should Not BeNullOrEmpty # Get-JiraIssue should be called once here to fetch the initial test issue Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It From 3e3d02bef40e5f23ea995f1a4ea4b9d17b808018 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 11:44:44 +0200 Subject: [PATCH 082/102] Move Test files --- {PSJira/Public => Tests}/Add-JiraIssueWatcher.Tests.ps1 | 0 {PSJira/Public => Tests}/Get-JiraIssueWatchers.Tests.ps1 | 0 {PSJira/Public => Tests}/Remove-JiraIssueWatcher.Tests.ps1 | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {PSJira/Public => Tests}/Add-JiraIssueWatcher.Tests.ps1 (100%) rename {PSJira/Public => Tests}/Get-JiraIssueWatchers.Tests.ps1 (100%) rename {PSJira/Public => Tests}/Remove-JiraIssueWatcher.Tests.ps1 (100%) diff --git a/PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 b/Tests/Add-JiraIssueWatcher.Tests.ps1 similarity index 100% rename from PSJira/Public/Add-JiraIssueWatcher.Tests.ps1 rename to Tests/Add-JiraIssueWatcher.Tests.ps1 diff --git a/PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 b/Tests/Get-JiraIssueWatchers.Tests.ps1 similarity index 100% rename from PSJira/Public/Get-JiraIssueWatchers.Tests.ps1 rename to Tests/Get-JiraIssueWatchers.Tests.ps1 diff --git a/PSJira/Public/Remove-JiraIssueWatcher.Tests.ps1 b/Tests/Remove-JiraIssueWatcher.Tests.ps1 similarity index 100% rename from PSJira/Public/Remove-JiraIssueWatcher.Tests.ps1 rename to Tests/Remove-JiraIssueWatcher.Tests.ps1 From 516f0f3229ee2ab4fa1f58e2d52b8bc8f7b5f61c Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 12:09:55 +0200 Subject: [PATCH 083/102] Rename File as Verbs should be in singular --- ...Get-JiraIssueWatchers.ps1 => Get-JiraIssueWatcher.ps1} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename PSJira/Public/{Get-JiraIssueWatchers.ps1 => Get-JiraIssueWatcher.ps1} (93%) diff --git a/PSJira/Public/Get-JiraIssueWatchers.ps1 b/PSJira/Public/Get-JiraIssueWatcher.ps1 similarity index 93% rename from PSJira/Public/Get-JiraIssueWatchers.ps1 rename to PSJira/Public/Get-JiraIssueWatcher.ps1 index e6c46536..01810f53 100644 --- a/PSJira/Public/Get-JiraIssueWatchers.ps1 +++ b/PSJira/Public/Get-JiraIssueWatcher.ps1 @@ -1,4 +1,4 @@ -function Get-JiraIssueWatchers +function Get-JiraIssueWatcher { <# .Synopsis @@ -6,10 +6,10 @@ .DESCRIPTION This function obtains watchers from existing issues in JIRA. .EXAMPLE - Get-JiraIssueWatchers -Key TEST-001 + Get-JiraIssueWatcher -Key TEST-001 This example returns all watchers posted to issue TEST-001. .EXAMPLE - Get-JiraIssue TEST-002 | Get-JiraIssueWatchers + Get-JiraIssue TEST-002 | Get-JiraIssueWatcher This example illustrates use of the pipeline to return all watchers on issue TEST-002. .INPUTS This function can accept PSJira.Issue objects, Strings, or Objects via the pipeline. It uses Get-JiraIssue to identify the issue parameter; see its Inputs section for details on how this function handles inputs. @@ -71,6 +71,6 @@ end { - Write-Debug "Completed Get-JiraIssueWatchers" + Write-Debug "Completed Get-JiraIssueWatcher" } } From 4a3d643852b8e5cea605deeb3e40338a81ec241c Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 12:10:14 +0200 Subject: [PATCH 084/102] Updated Unit Tests to us shared components --- Tests/Add-JiraIssueWatcher.Tests.ps1 | 57 +++++++------ Tests/Get-JiraIssueWatcher.Tests.ps1 | 103 ++++++++++++++++++++++++ Tests/Get-JiraIssueWatchers.Tests.ps1 | 101 ----------------------- Tests/Remove-JiraIssueWatcher.Tests.ps1 | 56 +++++++------ 4 files changed, 164 insertions(+), 153 deletions(-) create mode 100644 Tests/Get-JiraIssueWatcher.Tests.ps1 delete mode 100644 Tests/Get-JiraIssueWatchers.Tests.ps1 diff --git a/Tests/Add-JiraIssueWatcher.Tests.ps1 b/Tests/Add-JiraIssueWatcher.Tests.ps1 index f1478781..5d616733 100644 --- a/Tests/Add-JiraIssueWatcher.Tests.ps1 +++ b/Tests/Add-JiraIssueWatcher.Tests.ps1 @@ -1,10 +1,10 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { - $ShowMockData = $false + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 $jiraServer = 'http://jiraserver.example.com' $issueID = 41701 @@ -18,25 +18,19 @@ InModuleScope PSJira { Mock Get-JiraIssue -ModuleName PSJira { [PSCustomObject] @{ - ID = $issueID; + ID = $issueID; Key = $issueKey; RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; } } Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { - if ($ShowMockData) { - Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan - Write-Host " [Method] $Method" -ForegroundColor Cyan - Write-Host " [URI] $URI" -ForegroundColor Cyan - } + ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' } # Generic catch-all. This will throw an exception if we forgot to mock something. Mock Invoke-JiraMethod -ModuleName PSJira { - Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed - Write-Host " [Method] $Method" -ForegroundColor DarkRed - Write-Host " [URI] $URI" -ForegroundColor DarkRed + ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' throw "Unidentified call to Invoke-JiraMethod" } @@ -44,24 +38,35 @@ InModuleScope PSJira { # Tests ############# - It "Adds a Watcher to an issue in JIRA" { - $WatcherResult = Add-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey - $WatcherResult | Should BeNullOrEmpty - - # Get-JiraIssue should be used to identiyf the issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + Context "Sanity checking" { + $command = Get-Command -Name Add-JiraIssueWatcher - # Invoke-JiraMethod should be used to add the Watcher - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + defParam $command 'Watcher' + defParam $command 'Issue' + defParam $command 'Credential' } - It "Accepts pipeline input from Get-JiraIssue" { - $WatcherResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWatcher -Watcher 'fred' - $WatcherResult | Should BeNullOrEmpty + Context "Behavior testing" { + + It "Adds a Watcher to an issue in JIRA" { + $WatcherResult = Add-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be used to identify the issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It - # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) + # Invoke-JiraMethod should be used to add the Watcher + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Accepts pipeline input from Get-JiraIssue" { + $WatcherResult = Get-JiraIssue -InputObject $issueKey | Add-JiraIssueWatcher -Watcher 'fred' + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } } } } diff --git a/Tests/Get-JiraIssueWatcher.Tests.ps1 b/Tests/Get-JiraIssueWatcher.Tests.ps1 new file mode 100644 index 00000000..a58fd981 --- /dev/null +++ b/Tests/Get-JiraIssueWatcher.Tests.ps1 @@ -0,0 +1,103 @@ +. $PSScriptRoot\Shared.ps1 + +InModuleScope PSJira { + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 + + $jiraServer = 'http://jiraserver.example.com' + $jiraServer = 'http://jiraserver.example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + + Describe "Get-JiraIssueWatcher" { + + + ## Sample straight from the API: + ## https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssueWatchers + $restResult = @" +{ + "self": "$jiraServer/jira/rest/api/2/issue/EX-1/watchers", + "isWatching": false, + "watchCount": 1, + "watchers": [ + { + "self": "$jiraServer/jira/rest/api/2/user?username=fred", + "name": "fred", + "displayName": "Fred F. User", + "active": false + } + ] +} +"@ + Mock Get-JiraConfigServer -ModuleName PSJira { + Write-Output $jiraServer + } + + Mock Get-JiraIssue -ModuleName PSJira { + [PSCustomObject] @{ + ID = $issueID; + Key = $issueKey; + RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; + } + } + + # Obtaining watchers from an issue...this is IT-3676 in the test environment + Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { + ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' + ConvertFrom-Json2 -InputObject $restResult + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName PSJira { + ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri','Method' + throw "Unidentified call to Invoke-JiraMethod" + } + + ############# + # Tests + ############# + + Context "Sanity checking" { + $command = Get-Command -Name Get-JiraIssueWatcher + + defParam $command 'Issue' + defParam $command 'Credential' + } + + Context "Behavior testing" { + + It "Obtains all Jira watchers from a Jira issue if the issue key is provided" { + $watchers = Get-JiraIssueWatcher -Issue $issueKey + $watchers | Should Not BeNullOrEmpty + @($watchers).Count | Should Be 1 + $watchers.Name | Should Be "fred" + $watchers.DisplayName | Should Be "Fred F. User" + $watchers.RestUrl | Should Be "$jiraServer/jira/rest/api/2/user?username=fred" + + # Get-JiraIssue should be called to identify the -Issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + + # Normally, this would be called once in Get-JiraIssue and a second time in Get-JiraIssueWatcher, but + # since we've mocked Get-JiraIssue out, it will only be called once. + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Obtains all Jira watchers from a Jira issue if the Jira object is provided" { + $issue = Get-JiraIssue -Key $issueKey + $watchers = Get-JiraIssueWatcher -Issue $issue + $watchers | Should Not BeNullOrEmpty + $watchers.name | Should Be "fred" + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Handles pipeline input from Get-JiraIssue" { + $watchers = Get-JiraIssue -Key $issueKey | Get-JiraIssueWatcher + $watchers | Should Not BeNullOrEmpty + $watchers.name | Should Be "fred" + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + } + } +} diff --git a/Tests/Get-JiraIssueWatchers.Tests.ps1 b/Tests/Get-JiraIssueWatchers.Tests.ps1 deleted file mode 100644 index ad01cdad..00000000 --- a/Tests/Get-JiraIssueWatchers.Tests.ps1 +++ /dev/null @@ -1,101 +0,0 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" - -InModuleScope PSJira { - Describe "Get-JiraIssueWatchers" { - - $ShowMockData = $false - - $jiraServer = 'http://jiraserver.example.com' - $issueID = 41701 - $issueKey = 'IT-3676' - - ## Sample straight from the API: - ## https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssueWatchers - $restResult = @" -{ - "self": "$jiraServer/jira/rest/api/2/issue/EX-1/watchers", - "isWatching": false, - "watchCount": 1, - "watchers": [ - { - "self": "$jiraServer/jira/rest/api/2/user?username=fred", - "name": "fred", - "displayName": "Fred F. User", - "active": false - } - ] -} -"@ - Mock Get-JiraConfigServer -ModuleName PSJira { - Write-Output $jiraServer - } - - Mock Get-JiraIssue -ModuleName PSJira { - [PSCustomObject] @{ - ID = $issueID; - Key = $issueKey; - RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; - } - } - - # Obtaining watchers from an issue...this is IT-3676 in the test environment - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { - if ($ShowMockData) - { - Write-Host " Mocked Invoke-JiraMethod with GET method" -ForegroundColor Cyan - Write-Host " [Method] $Method" -ForegroundColor Cyan - Write-Host " [URI] $URI" -ForegroundColor Cyan - } - ConvertFrom-Json2 -InputObject $restResult - } - - # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { - Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed - Write-Host " [Method] $Method" -ForegroundColor DarkRed - Write-Host " [URI] $URI" -ForegroundColor DarkRed - throw "Unidentified call to Invoke-JiraMethod" - } - -# Mock Write-Debug { -# Write-Host "DEBUG: $Message" -ForegroundColor Yellow -# } - - ############# - # Tests - ############# - - It "Obtains all Jira watchers from a Jira issue if the issue key is provided" { - $watchers = Get-JiraIssueWatchers -Issue $issueKey - $watchers | Should Not BeNullOrEmpty - @($watchers).Count | Should Be 1 - $watchers.Name | Should Be "fred" - $watchers.DisplayName | Should Be "Fred F. User" - $watchers.RestUrl | Should Be "$jiraServer/jira/rest/api/2/user?username=fred" - - # Get-JiraIssue should be called to identify the -Issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It - - # Normally, this would be called once in Get-JiraIssue and a second time in Get-JiraIssueWatchers, but - # since we've mocked Get-JiraIssue out, it will only be called once. - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It - } - - It "Obtains all Jira watchers from a Jira issue if the Jira object is provided" { - $issue = Get-JiraIssue -Key $issueKey - $watchers = Get-JiraIssueWatchers -Issue $issue - $watchers | Should Not BeNullOrEmpty - $watchers.name | Should Be "fred" - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It - } - - It "Handles pipeline input from Get-JiraIssue" { - $watchers = Get-JiraIssue -Key $issueKey | Get-JiraIssueWatchers - $watchers | Should Not BeNullOrEmpty - $watchers.name | Should Be "fred" - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It - } - } -} diff --git a/Tests/Remove-JiraIssueWatcher.Tests.ps1 b/Tests/Remove-JiraIssueWatcher.Tests.ps1 index 34e2c374..bad446fc 100644 --- a/Tests/Remove-JiraIssueWatcher.Tests.ps1 +++ b/Tests/Remove-JiraIssueWatcher.Tests.ps1 @@ -1,10 +1,10 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") -. "$here\$sut" +. $PSScriptRoot\Shared.ps1 InModuleScope PSJira { - $ShowMockData = $false + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] + $SuppressImportModule = $true + . $PSScriptRoot\Shared.ps1 $jiraServer = 'http://jiraserver.example.com' $issueID = 41701 @@ -25,19 +25,12 @@ InModuleScope PSJira { } Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'DELETE' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers?username=fred"} { - if ($ShowMockData) - { - Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan - Write-Host " [Method] $Method" -ForegroundColor Cyan - Write-Host " [URI] $URI" -ForegroundColor Cyan - } + ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' } # Generic catch-all. This will throw an exception if we forgot to mock something. Mock Invoke-JiraMethod -ModuleName PSJira { - Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed - Write-Host " [Method] $Method" -ForegroundColor DarkRed - Write-Host " [URI] $URI" -ForegroundColor DarkRed + ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' throw "Unidentified call to Invoke-JiraMethod" } @@ -45,24 +38,35 @@ InModuleScope PSJira { # Tests ############# - It "Removes a Watcher from an issue in JIRA" { - $WatcherResult = Remove-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey - $WatcherResult | Should BeNullOrEmpty - - # Get-JiraIssue should be used to identiyf the issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + Context "Sanity checking" { + $command = Get-Command -Name Remove-JiraIssueWatcher - # Invoke-JiraMethod should be used to add the Watcher - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + defParam $command 'Watcher' + defParam $command 'Issue' + defParam $command 'Credential' } - It "Accepts pipeline input from Get-JiraIssue" { - $WatcherResult = Get-JiraIssue -InputObject $issueKey | Remove-JiraIssueWatcher -Watcher 'fred' - $WatcherResult | Should BeNullOrEmpty + Context "Behavior testing" { + + It "Removes a Watcher from an issue in JIRA" { + $WatcherResult = Remove-JiraIssueWatcher -Watcher 'fred' -Issue $issueKey + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be used to identiyf the issue parameter + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It - # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) + # Invoke-JiraMethod should be used to add the Watcher + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } + + It "Accepts pipeline input from Get-JiraIssue" { + $WatcherResult = Get-JiraIssue -InputObject $issueKey | Remove-JiraIssueWatcher -Watcher 'fred' + $WatcherResult | Should BeNullOrEmpty + + # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + } } } } From 1f61a714b208735fa804241b5a5eb86333400fbc Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 15:45:04 +0200 Subject: [PATCH 085/102] Added PSScriptAnalyzer to Unit Tests --- Rules/PSUsePascalCasing.psm1 | 29 ++++++++++++++++++++++++ Tests/PSJira.Tests.ps1 | 43 ++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 Rules/PSUsePascalCasing.psm1 diff --git a/Rules/PSUsePascalCasing.psm1 b/Rules/PSUsePascalCasing.psm1 new file mode 100644 index 00000000..182f8164 --- /dev/null +++ b/Rules/PSUsePascalCasing.psm1 @@ -0,0 +1,29 @@ +function Test-FunctionCasing { + [CmdletBinding()] + [OutputType([PSCustomObject[]])] + param ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.Language.ScriptBlockAst]$ScriptBlockAst + ) + + process { + try { + $functions = $ScriptBlockAst.FindAll( + { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] -and + $args[0].Name -cmatch '[A-Z]{2,}' + }, $true ) + foreach ( $function in $functions ) { + [PSCustomObject]@{ + Message = "Avoid function names with adjacent caps in their name" + Extent = $function.Extent + RuleName = $PSCmdlet.MyInvocation.InvocationName + Severity = "Warning" + } + } + } + catch { + $PSCmdlet.ThrowTerminatingError( $_ ) + } + } +} diff --git a/Tests/PSJira.Tests.ps1 b/Tests/PSJira.Tests.ps1 index 5859dbcb..8978b783 100644 --- a/Tests/PSJira.Tests.ps1 +++ b/Tests/PSJira.Tests.ps1 @@ -1,3 +1,5 @@ +#Requires -Modules PSScriptAnalyzer + $here = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = Split-Path -Parent $here $moduleRoot = "$projectRoot\PSJira" @@ -143,49 +145,58 @@ Describe "PSJira" { # goes to him for these tests. $files = @( - Get-ChildItem $here -Include *.ps1,*.psm1 - Get-ChildItem $publicFunctions -Include *.ps1,*.psm1 -Recurse + Get-ChildItem $here -Include *.ps1, *.psm1 + Get-ChildItem $publicFunctions -Include *.ps1, *.psm1 -Recurse ) It 'Source files contain no trailing whitespace' { $badLines = @( - foreach ($file in $files) - { + foreach ($file in $files) { $lines = [System.IO.File]::ReadAllLines($file.FullName) $lineCount = $lines.Count - for ($i = 0; $i -lt $lineCount; $i++) - { - if ($lines[$i] -match '\s+$') - { + for ($i = 0; $i -lt $lineCount; $i++) { + if ($lines[$i] -match '\s+$') { 'File: {0}, Line: {1}' -f $file.FullName, ($i + 1) } } } ) - if ($badLines.Count -gt 0) - { + if ($badLines.Count -gt 0) { throw "The following $($badLines.Count) lines contain trailing whitespace: `r`n`r`n$($badLines -join "`r`n")" } } It 'Source files all end with a newline' { $badFiles = @( - foreach ($file in $files) - { + foreach ($file in $files) { $string = [System.IO.File]::ReadAllText($file.FullName) - if ($string.Length -gt 0 -and $string[-1] -ne "`n") - { + if ($string.Length -gt 0 -and $string[-1] -ne "`n") { $file.FullName } } ) - if ($badFiles.Count -gt 0) - { + if ($badFiles.Count -gt 0) { throw "The following files do not end with a newline: `r`n`r`n$($badFiles -join "`r`n")" } } } + + Context 'PSScriptAnalyzer Rules' { + $analysis = Invoke-ScriptAnalyzer -Path .\PSJira -Recurse -Settings ".\ScriptAnalyzerSettings.psd1" -CustomRulePath "$PSScriptRoot\..\Rules\" -IncludeDefaultRules + $scriptAnalyzerRules = Get-ScriptAnalyzerRule + + forEach ($rule in $scriptAnalyzerRules) { + It "Should pass $rule" { + If ($analysis.RuleName -contains $rule) { + $analysis | + Where RuleName -EQ $rule -OutVariable failures | + Out-Default + $failures.Count | Should Be 0 + } + } + } + } } From 4087d499b718bae4320551047d03e3af6bdc891e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 15:45:30 +0200 Subject: [PATCH 086/102] Rename unapproved verbs --- PSJira/Internal/ConvertFrom-Json2.ps1 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/PSJira/Internal/ConvertFrom-Json2.ps1 b/PSJira/Internal/ConvertFrom-Json2.ps1 index 5fac46ba..82f19096 100644 --- a/PSJira/Internal/ConvertFrom-Json2.ps1 +++ b/PSJira/Internal/ConvertFrom-Json2.ps1 @@ -13,7 +13,7 @@ function ConvertFrom-Json2 ) begin { - function PopulateJsonFrom-Dictionary + function ConvertFrom-Dictionary { param ( @@ -30,11 +30,11 @@ function ConvertFrom-Json2 if ($pairObjectValue -is [System.Collections.Generic.IDictionary`2].MakeGenericType([String],[Object])) { - $pairObjectValue = PopulateJsonFrom-Dictionary $pairObjectValue + $pairObjectValue = ConvertFrom-Dictionary $pairObjectValue } elseif ($pairObjectValue -is [System.Collections.Generic.ICollection`1].MakeGenericType([Object])) { - $pairObjectValue = PopulateJsonFrom-Collection $pairObjectValue + $pairObjectValue = ConvertFrom-Collection $pairObjectValue } $returnObject | Add-Member Noteproperty $key $pairObjectValue @@ -44,7 +44,7 @@ function ConvertFrom-Json2 } } - function PopulateJsonFrom-Collection + function ConvertFrom-Collection { param ( @@ -60,11 +60,11 @@ function ConvertFrom-Json2 if ($jsonObjectValue -is [System.Collections.Generic.IDictionary`2].MakeGenericType([String],[Object])) { - $jsonObjectValue = PopulateJsonFrom-Dictionary $jsonObjectValue + $jsonObjectValue = ConvertFrom-Dictionary $jsonObjectValue } elseif ($jsonObjectValue -is [System.Collections.Generic.ICollection`1].MakeGenericType([Object])) { - $jsonObjectValue = PopulateJsonFrom-Collection $jsonObjectValue + $jsonObjectValue = ConvertFrom-Collection $jsonObjectValue } $returnList.Add($jsonObjectValue) | Out-Null @@ -118,11 +118,11 @@ public class JsonObjectTypeResolver : System.Web.Script.Serialization.JavaScript if ($jsonTree -is [System.Collections.Generic.IDictionary`2].MakeGenericType([String],[Object])) { - $jsonTree = PopulateJsonFrom-Dictionary $jsonTree + $jsonTree = ConvertFrom-Dictionary $jsonTree } elseif ($jsonTree -is [System.Collections.Generic.ICollection`1].MakeGenericType([Object])) { - $jsonTree = PopulateJsonFrom-Collection $jsonTree + $jsonTree = ConvertFrom-Collection $jsonTree } Write-Output $jsonTree From 72a6164578dca64124f5519a8866af3116dd151d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 15:45:54 +0200 Subject: [PATCH 087/102] Fix $null comparison --- PSJira/Internal/ConvertTo-JiraCreateMetaField.ps1 | 2 +- PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 | 2 +- PSJira/Internal/Invoke-JiraMethod.ps1 | 2 +- PSJira/Public/Set-JiraIssueLabel.ps1 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraCreateMetaField.ps1 b/PSJira/Internal/ConvertTo-JiraCreateMetaField.ps1 index f7139356..0dce8f46 100644 --- a/PSJira/Internal/ConvertTo-JiraCreateMetaField.ps1 +++ b/PSJira/Internal/ConvertTo-JiraCreateMetaField.ps1 @@ -65,7 +65,7 @@ function ConvertTo-JiraCreateMetaField foreach ($extraProperty in (Get-Member -InputObject $item -MemberType NoteProperty).Name) { # Write-Debug "[ConvertTo-JiraCreateMetaField] Checking property $extraProperty" - if ($props.$extraProperty -eq $null) + if ($null -eq $props.$extraProperty) { # Write-Debug "[ConvertTo-JiraCreateMetaField] - Adding property [$extraProperty]" $props.$extraProperty = $item.$extraProperty diff --git a/PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 b/PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 index 958a2ef0..061274f3 100644 --- a/PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 +++ b/PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 @@ -65,7 +65,7 @@ function ConvertTo-JiraEditMetaField foreach ($extraProperty in (Get-Member -InputObject $item -MemberType NoteProperty).Name) { # Write-Debug "[ConvertTo-JiraEditMetaField] Checking property $extraProperty" - if ($props.$extraProperty -eq $null) + if ($null -eq $props.$extraProperty) { # Write-Debug "[ConvertTo-JiraEditMetaField] - Adding property [$extraProperty]" $props.$extraProperty = $item.$extraProperty diff --git a/PSJira/Internal/Invoke-JiraMethod.ps1 b/PSJira/Internal/Invoke-JiraMethod.ps1 index 8796fcfe..c97ecbb5 100644 --- a/PSJira/Internal/Invoke-JiraMethod.ps1 +++ b/PSJira/Internal/Invoke-JiraMethod.ps1 @@ -110,7 +110,7 @@ function Invoke-JiraMethod } } - if ($result.errors -ne $null) + if ($null -ne $result.errors) { Write-Debug "[Invoke-JiraMethod] An error response was received from JIRA; resolving" Resolve-JiraError $result -WriteError diff --git a/PSJira/Public/Set-JiraIssueLabel.ps1 b/PSJira/Public/Set-JiraIssueLabel.ps1 index b4a9b9ac..6f58f4db 100644 --- a/PSJira/Public/Set-JiraIssueLabel.ps1 +++ b/PSJira/Public/Set-JiraIssueLabel.ps1 @@ -104,7 +104,7 @@ Write-Debug "[Set-JiraIssueLabel] Set parameter was used; existing labels will be overwritten" $newLabels = $Set } - elseif ($currentLabels -eq $null -or $currentLabels.Count -eq 0) + elseif ($null -eq $currentLabels -or $currentLabels.Count -eq 0) { Write-Debug "[Set-JiraIssueLabel] Issue currently has no labels" if ($Add) From 0a2b6d9a129337366cb908c02feca595dbcece00 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 16:40:49 +0200 Subject: [PATCH 088/102] Remove unused variables --- PSJira/Internal/ConvertTo-JiraField.ps1 | 4 ++-- PSJira/Internal/ConvertTo-JiraIssueType.ps1 | 4 ++-- PSJira/Internal/ConvertTo-JiraPriority.ps1 | 4 ++-- PSJira/Public/Get-JiraIssueCreateMetadata.ps1 | 4 ++-- PSJira/Public/Get-JiraIssueEditMetadata.ps1 | 4 ++-- PSJira/Public/Get-JiraUser.ps1 | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraField.ps1 b/PSJira/Internal/ConvertTo-JiraField.ps1 index 57a44ded..5ebb3df3 100644 --- a/PSJira/Internal/ConvertTo-JiraField.ps1 +++ b/PSJira/Internal/ConvertTo-JiraField.ps1 @@ -36,8 +36,8 @@ function ConvertTo-JiraField Write-Output $result } } else { - $server = ($InputObject.self -split 'rest')[0] - $http = "${server}browse/$($i.key)" + # $server = ($InputObject.self -split 'rest')[0] + # $http = "${server}browse/$($i.key)" # Write-Debug "[ConvertTo-JiraField] Defining standard properties" $props = @{ diff --git a/PSJira/Internal/ConvertTo-JiraIssueType.ps1 b/PSJira/Internal/ConvertTo-JiraIssueType.ps1 index 1bfbff4c..8b6c6714 100644 --- a/PSJira/Internal/ConvertTo-JiraIssueType.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssueType.ps1 @@ -36,8 +36,8 @@ function ConvertTo-JiraIssueType Write-Output $result } } else { - $server = ($InputObject.self -split 'rest')[0] - $http = "${server}browse/$($i.key)" + # $server = ($InputObject.self -split 'rest')[0] + # $http = "${server}browse/$($i.key)" # Write-Debug "[ConvertTo-JiraIssueType] Defining standard properties" $props = @{ diff --git a/PSJira/Internal/ConvertTo-JiraPriority.ps1 b/PSJira/Internal/ConvertTo-JiraPriority.ps1 index 596a0bea..79b93783 100644 --- a/PSJira/Internal/ConvertTo-JiraPriority.ps1 +++ b/PSJira/Internal/ConvertTo-JiraPriority.ps1 @@ -36,8 +36,8 @@ function ConvertTo-JiraPriority Write-Output $result } } else { - $server = ($InputObject.self -split 'rest')[0] - $http = "${server}browse/$($i.key)" + # $server = ($InputObject.self -split 'rest')[0] + # $http = "${server}browse/$($i.key)" # Write-Debug "[ConvertTo-JiraPriority] Defining standard properties" $props = @{ diff --git a/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 b/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 index 9a797eaf..2a049276 100644 --- a/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 +++ b/PSJira/Public/Get-JiraIssueCreateMetadata.ps1 @@ -102,8 +102,8 @@ function Get-JiraIssueCreateMetadata throw "Multiple projects were found for the given project [$Project]. Refine the parameters to return only one project." } - $projectId = $jiraResult.projects.id - $projectKey = $jiraResult.projects.key + # $projectId = $jiraResult.projects.id + # $projectKey = $jiraResult.projects.key Write-Debug "[Get-JiraIssueCreateMetadata] Identified project key: [$Project]" diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 index 5691ee0c..95b172b3 100644 --- a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 +++ b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 @@ -71,8 +71,8 @@ function Get-JiraIssueEditMetadata throw "Multiple projects were found for the given project [$Project]. Refine the parameters to return only one project." } - $projectId = $jiraResult.projects.id - $projectKey = $jiraResult.projects.key + # $projectId = $jiraResult.projects.id + # $projectKey = $jiraResult.projects.key Write-Debug "[Get-JiraIssueEditMetadata] Identified project key: [$Project]" diff --git a/PSJira/Public/Get-JiraUser.ps1 b/PSJira/Public/Get-JiraUser.ps1 index 5d101c61..7a0e7f58 100644 --- a/PSJira/Public/Get-JiraUser.ps1 +++ b/PSJira/Public/Get-JiraUser.ps1 @@ -58,7 +58,7 @@ function Get-JiraUser $userSearchUrl = "$userSearchUrl&includeInactive=true" } - $userGetUrl = "$server/rest/api/latest/user?username={0}&expand=groups" + # $userGetUrl = "$server/rest/api/latest/user?username={0}&expand=groups" } process From df031a199faa6991bbb742e226b3aadc12c3f51d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 16:41:48 +0200 Subject: [PATCH 089/102] Declare SupportsShouldProcess --- PSJira/Public/New-JiraGroup.ps1 | 16 ++-- PSJira/Public/New-JiraIssue.ps1 | 9 ++- PSJira/Public/New-JiraSession.ps1 | 29 +++---- PSJira/Public/New-JiraUser.ps1 | 9 ++- PSJira/Public/Remove-JiraSession.ps1 | 48 ++++-------- PSJira/Public/Set-JiraConfigServer.ps1 | 30 +++---- PSJira/Public/Set-JiraIssue.ps1 | 104 ++++++++++--------------- PSJira/Public/Set-JiraIssueLabel.ps1 | 64 +++++++-------- PSJira/Public/Set-JiraUser.ps1 | 60 ++++++-------- 9 files changed, 151 insertions(+), 218 deletions(-) diff --git a/PSJira/Public/New-JiraGroup.ps1 b/PSJira/Public/New-JiraGroup.ps1 index 750c2715..13914c33 100644 --- a/PSJira/Public/New-JiraGroup.ps1 +++ b/PSJira/Public/New-JiraGroup.ps1 @@ -13,7 +13,7 @@ .OUTPUTS [PSJira.Group] The user object created #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $true)] param( # Name for the new group. [Parameter(Mandatory = $true, @@ -54,16 +54,16 @@ Write-Debug "[New-JiraGroup] Converting to JSON" $json = ConvertTo-Json -InputObject $props - Write-Debug "[New-JiraGroup] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Post -URI $restUrl -Body $json -Credential $Credential - - if ($result) - { + Write-Debug "[New-JiraGroup] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($GroupName, "Creating group [$GroupName] to JIRA")) { + Write-Debug "[New-JiraGroup] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Post -URI $restUrl -Body $json -Credential $Credential + } + if ($result) { Write-Debug "[New-JiraGroup] Converting output object into a Jira user and outputting" ConvertTo-JiraGroup -InputObject $result } - else - { + else { Write-Debug "[New-JiraGroup] Jira returned no results to output." } } diff --git a/PSJira/Public/New-JiraIssue.ps1 b/PSJira/Public/New-JiraIssue.ps1 index 2ed2779e..d649ee99 100644 --- a/PSJira/Public/New-JiraIssue.ps1 +++ b/PSJira/Public/New-JiraIssue.ps1 @@ -27,7 +27,7 @@ function New-JiraIssue .OUTPUTS [PSJira.Issue] The issue created in JIRA. #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $true)] param( # Project in which to create the issue. [Parameter(Mandatory = $true)] @@ -219,8 +219,11 @@ function New-JiraIssue Write-Debug "[New-JiraIssue] Converting to JSON" $json = ConvertTo-Json -InputObject $hashtable -Depth 3 - Write-Debug "[New-JiraIssue] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Post -URI $issueURL -Body $json -Credential $Credential + Write-Debug "[New-JiraIssue] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($Summary, "Creating new Issue on JIRA")) { + Write-Debug "[New-JiraIssue] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Post -URI $issueURL -Body $json -Credential $Credential + } if ($result) { diff --git a/PSJira/Public/New-JiraSession.ps1 b/PSJira/Public/New-JiraSession.ps1 index c7afa87a..4ca1b539 100644 --- a/PSJira/Public/New-JiraSession.ps1 +++ b/PSJira/Public/New-JiraSession.ps1 @@ -1,5 +1,4 @@ -function New-JiraSession -{ +function New-JiraSession { <# .Synopsis Creates a persistent JIRA authenticated session which can be used by other PSJira functions @@ -22,7 +21,8 @@ function New-JiraSession .OUTPUTS [PSJira.Session] An object representing the Jira session #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $false)] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( # Credentials to use to connect to JIRA. [Parameter(Mandatory = $true, @@ -30,14 +30,11 @@ function New-JiraSession [System.Management.Automation.PSCredential] $Credential ) - begin - { - try - { + begin { + try { Write-Debug "[New-JiraSession] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch - { + } catch { $err = $_ Write-Debug "[New-JiraSession] Encountered an error reading configuration data." throw $err @@ -54,8 +51,7 @@ function New-JiraSession } } - process - { + process { $hashtable = @{ 'username' = $Credential.UserName; 'password' = $Credential.GetNetworkCredential().Password; @@ -65,8 +61,7 @@ function New-JiraSession Write-Debug "[New-JiraSession] Created JSON syntax in variable `$json." Write-Debug "[New-JiraSession] Preparing for blastoff!" - try - { + try { $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Post -Body $json -UseBasicParsing -SessionVariable newSessionVar Write-Debug "[New-JiraSession] Converting result to JiraSession object" $result = ConvertTo-JiraSession -WebResponse $webResponse -Session $newSessionVar -Username $Credential.UserName @@ -77,8 +72,7 @@ function New-JiraSession Write-Debug "[New-JiraSession] Adding session result to existing module PrivateData" $MyInvocation.MyCommand.Module.PrivateData.Session = $result; } - else - { + else { Write-Debug "[New-JiraSession] Creating module PrivateData" $MyInvocation.MyCommand.Module.PrivateData = @{ 'Session' = $result; @@ -87,14 +81,13 @@ function New-JiraSession Write-Debug "[New-JiraSession] Outputting result" Write-Output $result - } catch - { + } catch { $err = $_ $webResponse = $err.Exception.Response Write-Debug "[New-JiraSession] Encountered an exception from the Jira server: $err" # Test HEADERS if Jira requires a CAPTCHA - $tokenRequiresCaptcha = "AUTHENTICATION_DENIED" + $tokenRequiresCaptcha = "AUTHENTICATION_DENIED" $headerRequiresCaptcha = "X-Seraph-LoginReason" if (($webResponse.Headers[$headerRequiresCaptcha] -split ",") -contains $tokenRequiresCaptcha) { Write-Warning "JIRA requires you to log on to the website before continuing for security reasons." diff --git a/PSJira/Public/New-JiraUser.ps1 b/PSJira/Public/New-JiraUser.ps1 index 756f74b6..e54a2516 100644 --- a/PSJira/Public/New-JiraUser.ps1 +++ b/PSJira/Public/New-JiraUser.ps1 @@ -22,7 +22,7 @@ function New-JiraUser .OUTPUTS [PSJira.User] The user object created #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $true)] param( # Name of user. [Parameter(Mandatory = $true)] @@ -87,8 +87,11 @@ function New-JiraUser Write-Debug "[New-JiraUser] Converting to JSON" $json = ConvertTo-Json -InputObject $props - Write-Debug "[New-JiraUser] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Post -URI $userURL -Body $json -Credential $Credential + Write-Debug "[New-JiraUser] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($UserName, "Creating new User on JIRA")) { + Write-Debug "[New-JiraUser] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Post -URI $userURL -Body $json -Credential $Credential + } if ($result) { diff --git a/PSJira/Public/Remove-JiraSession.ps1 b/PSJira/Public/Remove-JiraSession.ps1 index e54c8d69..76ceb437 100644 --- a/PSJira/Public/Remove-JiraSession.ps1 +++ b/PSJira/Public/Remove-JiraSession.ps1 @@ -1,5 +1,4 @@ -function Remove-JiraSession -{ +function Remove-JiraSession { <# .Synopsis Removes a persistent JIRA authenticated session @@ -27,7 +26,8 @@ function Remove-JiraSession .OUTPUTS [PSJira.Session] An object representing the Jira session #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $false)] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( # A Jira session to be closed. If not specified, this function will use a saved session. [Parameter(Mandatory = $false, @@ -36,14 +36,11 @@ function Remove-JiraSession [Object] $Session ) - begin - { - try - { + begin { + try { Write-Debug "[Remove-JiraSession] Reading Jira server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch - { + } catch { $err = $_ Write-Debug "[Remove-JiraSession] Encountered an error reading configuration data." throw $err @@ -56,43 +53,34 @@ function Remove-JiraSession } } - process - { - if ($Session) - { + process { + if ($Session) { Write-Debug "[Remove-JiraSession] Validating Session parameter" - if ((Get-Member -InputObject $Session).TypeName -eq 'PSJira.Session') - { + if ((Get-Member -InputObject $Session).TypeName -eq 'PSJira.Session') { Write-Debug "[Remove-JiraSession] Successfully parsed Session parameter as a PSJira.Session object" } - else - { + else { Write-Debug "[Remove-JiraSession] Session parameter is not a PSJira.Session object. Throwing exception" throw "Unable to parse parameter [$Session] as a PSJira.Session object" } } - else - { + else { Write-Debug "[Remove-JiraSession] Session parameter was not supplied. Checking for saved session in module PrivateData" $Session = Get-JiraSession } - if ($Session) - { + if ($Session) { Write-Debug "[Remove-JiraSession] Preparing for blastoff!" - try - { + try { $webResponse = Invoke-WebRequest -Uri $uri -Headers $headers -Method Delete -WebSession $Session.WebSession Write-Debug "[Remove-JiraSession] Removing session from module's PrivateData" - if ($MyInvocation.MyCommand.Module.PrivateData) - { + if ($MyInvocation.MyCommand.Module.PrivateData) { Write-Debug "[Remove-JiraSession] Removing session from existing module PrivateData" $MyInvocation.MyCommand.Module.PrivateData.Session = $null; } - else - { + else { Write-Debug "[Remove-JiraSession] Creating module PrivateData" $MyInvocation.MyCommand.Module.PrivateData = @{ 'Session' = $null; @@ -112,12 +100,10 @@ function Remove-JiraSession $body = $readStream.ReadToEnd() $readStream.Close() Write-Debug "Retrieved body of HTTP response for more information about the error (`$body)" - $result = ConvertFrom-Json2 -InputObject $body - Write-Debug "Converted body from JSON into PSCustomObject (`$result)" + ConvertFrom-Json2 -InputObject $body } } - else - { + else { Write-Verbose "No Jira session is saved." } } diff --git a/PSJira/Public/Set-JiraConfigServer.ps1 b/PSJira/Public/Set-JiraConfigServer.ps1 index af226c05..9e02d1eb 100644 --- a/PSJira/Public/Set-JiraConfigServer.ps1 +++ b/PSJira/Public/Set-JiraConfigServer.ps1 @@ -1,5 +1,4 @@ -function Set-JiraConfigServer -{ +function Set-JiraConfigServer { <# .Synopsis Defines the configured URL for the JIRA server @@ -18,7 +17,8 @@ function Set-JiraConfigServer .NOTES Support for multiple configuration files is limited at this point in time, but enhancements are planned for a future update. #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $false)] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( # The base URL of the Jira instance. [Parameter(Mandatory = $true, @@ -36,8 +36,7 @@ function Set-JiraConfigServer # want to default to the script variable just as we would if the parameter was not # provided at all. - if (-not ($ConfigFile)) - { + if (-not ($ConfigFile)) { # Write-Debug "[Set-JiraConfigServer] ConfigFile was not provided, or provided with a null value" # This file should be in $moduleRoot/Functions/Internal, so PSScriptRoot will be $moduleRoot/Functions $moduleFolder = Split-Path -Path $PSScriptRoot -Parent @@ -46,35 +45,30 @@ function Set-JiraConfigServer # Write-Debug "[Set-JiraConfigServer] Using default config file at [$ConfigFile]" } - if (-not (Test-Path -Path $ConfigFile)) - { + if (-not (Test-Path -Path $ConfigFile)) { # Write-Debug "[Set-JiraConfigServer] Creating config file '$ConfigFile'" $xml = [XML] '' } - else - { + else { # Write-Debug "[Set-JiraConfigServer] Loading config file '$ConfigFile'" $xml = New-Object -TypeName XML $xml.Load($ConfigFile) } $xmlConfig = $xml.DocumentElement - if ($xmlConfig.LocalName -ne 'Config') - { + if ($xmlConfig.LocalName -ne 'Config') { throw "Unexpected document element [$($xmlConfig.LocalName)] in configuration file. You may need to delete the config file and recreate it using this function." } # Check for trailing slash and strip it if necessary $fixedServer = $Server.Trim() - if ($fixedServer.EndsWith('/') -or $fixedServer.EndsWith('\')) - { + if ($fixedServer.EndsWith('/') -or $fixedServer.EndsWith('\')) { $fixedServer = $Server.Substring(0, $Server.Length - 1) } - if ($xmlConfig.Server) - { + if ($xmlConfig.Server) { # Write-Debug "[Set-JiraConfigServer] Changing the existing Server element to the provided value '$Server'" $xmlConfig.Server = $fixedServer } @@ -89,11 +83,9 @@ function Set-JiraConfigServer } # Write-Debug "[Set-JiraConfigServer] Saving XML file" - try - { + try { $xml.Save($ConfigFile) - } catch - { + } catch { $err = $_ # Write-Debug "[Set-JiraConfigServer] Encountered an error saving the XML file" # Write-Debug "[Set-JiraConfigServer] Throwing exception" diff --git a/PSJira/Public/Set-JiraIssue.ps1 b/PSJira/Public/Set-JiraIssue.ps1 index 3b27aba4..6503ee95 100644 --- a/PSJira/Public/Set-JiraIssue.ps1 +++ b/PSJira/Public/Set-JiraIssue.ps1 @@ -1,5 +1,4 @@ -function Set-JiraIssue -{ +function Set-JiraIssue { <# .Synopsis Modifies an existing issue in JIRA @@ -23,7 +22,10 @@ function Set-JiraIssue If the -PassThru parameter is provided, this function will provide a reference to the JIRA issue modified. Otherwise, this function does not provide output. #> - [CmdletBinding(DefaultParameterSetName = 'ByInputObject')] + [CmdletBinding( + SupportsShouldProcess = $true, + DefaultParameterSetName = 'ByInputObject' + )] param( # Issue key or PSJira.Issue object returned from Get-JiraIssue. [Parameter(Mandatory = $true, @@ -59,7 +61,7 @@ function Set-JiraIssue [System.Collections.Hashtable] $Fields, # Path of the file where the configuration is stored. - [ValidateScript({Test-Path $_})] + [ValidateScript( {Test-Path $_})] [String] $ConfigFile, # Credentials to use to connect to JIRA. @@ -71,40 +73,30 @@ function Set-JiraIssue [Switch] $PassThru ) - begin - { + begin { Write-Debug "[Set-JiraIssue] Checking to see if we have any operations to perform" $fieldNames = $Fields.Keys - if (-not ($Summary -or $Description -or $Assignee -or $Label -or $FixVersion -or $fieldNames)) - { + if (-not ($Summary -or $Description -or $Assignee -or $Label -or $FixVersion -or $fieldNames)) { Write-Verbose "Nothing to do." return } - Write-Debug "[Set-JiraIssue] Reading server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - - if ($Assignee) - { + if ($Assignee) { Write-Debug "[Set-JiraIssue] Testing Assignee type" - if ($Assignee -eq 'Unassigned') - { + if ($Assignee -eq 'Unassigned') { Write-Debug "[Set-JiraIssue] 'Unassigned' String passed. Issue will be assigned to no one." $assigneeString = "" $validAssignee = $true } - else - { + else { Write-Debug "[Set-JiraIssue] Attempting to obtain Jira user [$Assignee]" $assigneeObj = Get-JiraUser -InputObject $Assignee -Credential $Credential - if ($assigneeObj) - { + if ($assigneeObj) { Write-Debug "[Set-JiraIssue] User found (name=[$($assigneeObj.Name)],RestUrl=[$($assigneeObj.RestUrl)])" $assigneeString = $assigneeObj.Name $validAssignee = $true } - else - { + else { Write-Debug "[Set-JiraIssue] Unable to obtain Assignee. Exception will be thrown." throw "Unable to validate Jira user [$Assignee]. Use Get-JiraUser for more details." } @@ -114,24 +106,20 @@ function Set-JiraIssue Write-Debug "[Set-JiraIssue] Completed Begin block." } - process - { - foreach ($i in $Issue) - { + process { + foreach ($i in $Issue) { $actOnIssueUri = $false $actOnAssigneeUri = $false Write-Debug "[Set-JiraIssue] Obtaining reference to issue" $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential - if ($issueObj) - { + if ($issueObj) { $issueProps = @{ 'update' = @{} } - if ($Summary) - { + if ($Summary) { # Update properties need to be passed to JIRA as arrays $issueProps.update.summary = @() $issueProps.update.summary += @{ @@ -140,8 +128,7 @@ function Set-JiraIssue $actOnIssueUri = $true } - if ($Description) - { + if ($Description) { $issueProps.update.description = @() $issueProps.update.description += @{ 'set' = $Description; @@ -149,11 +136,9 @@ function Set-JiraIssue $actOnIssueUri = $true } - If($FixVersion) - { + If ($FixVersion) { $fixVersionSet = @() - Foreach($f in $FixVersion) - { + Foreach ($f in $FixVersion) { $fixVersionSet += @{ 'name' = $f } @@ -165,18 +150,15 @@ function Set-JiraIssue $actOnIssueUri = $true } - if ($Fields) - { + if ($Fields) { Write-Debug "[Set-JiraIssue] Validating field names" - foreach ($k in $Fields.Keys) - { + foreach ($k in $Fields.Keys) { $name = $k $value = $Fields.$k Write-Debug "[Set-JiraIssue] Attempting to identify field (name=[$name], value=[$value])" $f = Get-JiraField -Field $name -Credential $Credential - if ($f) - { + if ($f) { # For some reason, this was coming through as a hashtable instead of a String, # which was causing ConvertTo-Json to crash later. # Not sure why, but this forces $id to be a String and not a hashtable. @@ -188,16 +170,14 @@ function Set-JiraIssue } $actOnIssueUri = $true } - else - { + else { Write-Debug "[Set-JiraIssue] Field [$name] could not be identified in Jira" throw "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." } } } - if ($validAssignee) - { + if ($validAssignee) { $assigneeProps = @{ 'name' = $assigneeString; } @@ -205,54 +185,52 @@ function Set-JiraIssue $actOnAssigneeUri = $true } - if ($actOnIssueUri) - { + if ($actOnIssueUri) { Write-Debug "[Set-JiraIssue] IssueProps: [$issueProps]" Write-Debug "[Set-JiraIssue] Converting results to JSON" $json = ConvertTo-Json -InputObject $issueProps -Depth 5 $issueObjURL = $issueObj.RestUrl - Write-Debug "[Set-JiraIssue] Preparing for blastoff!" - $issueResult = Invoke-JiraMethod -Method Put -URI $issueObjURL -Body $json -Credential $Credential - Write-Debug "[Set-JiraIssue] Results are saved to issueResult variable" + Write-Debug "[Set-JiraIssue] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($Issue, "Updating Issue [$IssueObj] from JIRA")) { + Write-Debug "[Set-JiraIssue] Preparing for blastoff!" + Invoke-JiraMethod -Method Put -URI $issueObjURL -Body $json -Credential $Credential + } } - if ($actOnAssigneeUri) - { + if ($actOnAssigneeUri) { # Jira handles assignee differently; you can't change it from the default "edit issues" screen unless # you customize the "Edit Issue" screen. $assigneeUrl = "{0}/assignee" -f $issueObj.RestUrl $json = ConvertTo-Json -InputObject $assigneeProps - Write-Debug "[Set-JiraIssue] Preparing for blastoff!" - $assigneeResult = Invoke-JiraMethod -Method Put -URI $assigneeUrl -Body $json -Credential $Credential - Write-Debug "[Set-JiraIssue] Results are saved to assigneeResult variable" + Write-Debug "[Set-JiraIssue] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($Issue, "Updating Issue [Assignee] from JIRA")) { + Write-Debug "[Set-JiraIssue] Preparing for blastoff!" + Invoke-JiraMethod -Method Put -URI $assigneeUrl -Body $json -Credential $Credential + } } - if ($Label) - { + if ($Label) { Write-Debug "[Set-JiraIssue] Invoking Set-JiraIssueLabel to set issue labels" Set-JiraIssueLabel -Issue $issueObj -Set $Label -Credential $Credential } - if ($PassThru) - { + if ($PassThru) { Write-Debug "[Set-JiraIssue] PassThru was specified. Obtaining updated reference to issue" Get-JiraIssue -Key $issueObj.Key -Credential $Credential } } - else - { + else { Write-Debug "[Set-JiraIssue] Unable to identify issue [$i]. Writing error message." Write-Error "Unable to identify issue [$i]" } } } - end - { + end { Write-Debug "[Set-JiraIssue] Complete" } } diff --git a/PSJira/Public/Set-JiraIssueLabel.ps1 b/PSJira/Public/Set-JiraIssueLabel.ps1 index 6f58f4db..c5e6ca69 100644 --- a/PSJira/Public/Set-JiraIssueLabel.ps1 +++ b/PSJira/Public/Set-JiraIssueLabel.ps1 @@ -1,5 +1,4 @@ -function Set-JiraIssueLabel -{ +function Set-JiraIssueLabel { <# .Synopsis Modifies labels on an existing JIRA issue @@ -29,7 +28,10 @@ If the -PassThru parameter is provided, this function will provide a reference to the JIRA issue modified. Otherwise, this function does not provide output. #> - [CmdletBinding(DefaultParameterSetName = 'ReplaceLabels')] + [CmdletBinding( + SupportsShouldProcess = $true, + DefaultParameterSetName = 'ReplaceLabels' + )] param( # Issue key or PSJira.Issue object returned from Get-JiraIssue. [Parameter(Mandatory = $true, @@ -67,21 +69,15 @@ [Switch] $PassThru ) - begin - { - Write-Debug "[Set-JiraIssueLabel] Reading server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + begin { } - process - { - foreach ($i in $Issue) - { + process { + foreach ($i in $Issue) { Write-Debug "[Set-JiraIssueLabel] Obtaining reference to issue" $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential - if ($issueObj) - { + if ($issueObj) { $currentLabels = @($issueObj.labels) $url = $issueObj.RestURL $isDirty = $true @@ -94,32 +90,26 @@ # issue object and use the Set verb for everything, so we only # have to make one call to JIRA. - if ($Clear) - { + if ($Clear) { Write-Debug "[Set-JiraIssueLabel] Clearing all labels" $newLabels = @() } - elseif ($PSCmdlet.ParameterSetName -eq 'ReplaceLabels') - { + elseif ($PSCmdlet.ParameterSetName -eq 'ReplaceLabels') { Write-Debug "[Set-JiraIssueLabel] Set parameter was used; existing labels will be overwritten" $newLabels = $Set } - elseif ($null -eq $currentLabels -or $currentLabels.Count -eq 0) - { + elseif ($null -eq $currentLabels -or $currentLabels.Count -eq 0) { Write-Debug "[Set-JiraIssueLabel] Issue currently has no labels" - if ($Add) - { + if ($Add) { Write-Debug "[Set-JiraIssueLabel] Setting labels to Add parameter" $newLabels = $Add } - else - { + else { Write-Debug "[Set-JiraIssueLabel] No labels were specified to be added; nothing to do" $isDirty = $false } } - else - { + else { Write-Debug "[Set-JiraIssueLabel] Calculating new labels" # If $Add is not provided (null), this can end up with an # extra $null being added to the array, so we need to @@ -128,8 +118,7 @@ $newLabels = $currentLabels + $Add | Where-Object -FilterScript {$_ -ne $null -and $Remove -notcontains $_} } - if ($isDirty) - { + if ($isDirty) { Write-Debug "[Set-JiraIssueLabel] New labels for the issue: [$($newLabels -join ',')]" $props = @{ @@ -146,31 +135,30 @@ $json = ConvertTo-Json -InputObject $props -Depth 4 Write-Debug "[Set-JiraIssueLabel] JSON:`n$json" - Write-Debug "[Set-JiraIssueLabel] Preparing for blastoff!" - # Should return no results - $result = Invoke-JiraMethod -Method Put -URI $url -Body $json -Credential $Credential + Write-Debug "[Remove-JiraGroup] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($Issue, "Updating Issue [labels] from JIRA")) { + Write-Debug "[Set-JiraIssueLabel] Preparing for blastoff!" + # Should return no results + Invoke-JiraMethod -Method Put -URI $url -Body $json -Credential $Credential + } } - else - { + else { Write-Debug "[Set-JiraIssueLabel] No changes are necessary." } - if ($PassThru) - { + if ($PassThru) { Write-Debug "[Set-JiraIssue] PassThru was specified. Obtaining updated reference to issue" Get-JiraIssue -Key $issueObj.Key -Credential $Credential } } - else - { + else { Write-Debug "[Set-JiraIssue] Unable to identify issue [$i]. Writing error message." Write-Error "Unable to identify issue [$i]" } } } - end - { + end { Write-Debug "[Set-JiraIssueLabel] Complete" } } diff --git a/PSJira/Public/Set-JiraUser.ps1 b/PSJira/Public/Set-JiraUser.ps1 index c0a24d31..0937902f 100644 --- a/PSJira/Public/Set-JiraUser.ps1 +++ b/PSJira/Public/Set-JiraUser.ps1 @@ -1,5 +1,4 @@ -function Set-JiraUser -{ +function Set-JiraUser { <# .Synopsis Modifies user properties in JIRA @@ -25,7 +24,10 @@ function Set-JiraUser If you'd like to see this ability added to JIRA and to this module, please vote on Atlassian's site for this issue: https://jira.atlassian.com/browse/JRA-37294 #> - [CmdletBinding(DefaultParameterSetName = 'ByNamedParameters')] + [CmdletBinding( + SupportsShouldProcess = $true, + DefaultParameterSetName = 'ByNamedParameters' + )] param( # Username or user object obtained from Get-JiraUser. [Parameter(Mandatory = $true, @@ -60,8 +62,7 @@ function Set-JiraUser [Switch] $PassThru ) - begin - { + begin { Write-Debug "[Set-JiraUser] Reading server from config file" $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop @@ -69,29 +70,23 @@ function Set-JiraUser $updateProps = @{} - if ($PSCmdlet.ParameterSetName -eq 'ByNamedParameters') - { - if (-not ($DisplayName -or $EmailAddress)) - { + if ($PSCmdlet.ParameterSetName -eq 'ByNamedParameters') { + if (-not ($DisplayName -or $EmailAddress)) { Write-Debug "[Set-JiraIssue] Nothing to do." return } - else - { + else { Write-Debug "[Set-JiraIssue] Building property hashtable" - if ($DisplayName) - { + if ($DisplayName) { $updateProps.displayName = $DisplayName } - if ($EmailAddress) - { + if ($EmailAddress) { $updateProps.emailAddress = $EmailAddress } } } - else - { + else { $updateProps = $Property } @@ -99,44 +94,39 @@ function Set-JiraUser $userUrl = "$server/rest/api/latest/user?username={0}" } - process - { - foreach ($u in $User) - { + process { + foreach ($u in $User) { Write-Debug "[Set-JiraUser] Obtaining reference to user [$u]" $userObj = Get-JiraUser -InputObject $u -Credential $Credential - if ($userObj) - { + if ($userObj) { $thisUrl = $userUrl -f $userObj.Name Write-Debug "[Set-JiraUser] User URL: [$thisUrl]" - Write-Debug "Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Put -URI $thisUrl -Body $updateProps -Credential $Credential - if ($result) - { + Write-Debug "[Set-JiraUser] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($User, "Updating user [$User] from JIRA")) { + Write-Debug "Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Put -URI $thisUrl -Body $updateProps -Credential $Credential + } + if ($result) { Write-Debug "[Set-JiraUser] JIRA returned results." - if ($PassThru) - { + if ($PassThru) { Write-Debug "[Set-JiraUser] PassThru flag was specified. Invoking Get-JiraUser to get an updated reference to user [$u]" Write-Output (Get-JiraUser -InputObject $u) } } - else - { + else { Write-Debug "[Set-JiraUser] JIRA returned no results to display." } } - else - { + else { Write-Debug "[Set-JiraUser] Unable to identify user [$u]. Writing error message." Write-Error "Unable to identify user [$u]" } } } - end - { + end { Write-Debug "[Set-JiraUser] Complete" } } From bce9c8e415d378978c9d1e15345e506c2434fd49 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 20 Jun 2017 16:42:20 +0200 Subject: [PATCH 090/102] Exclude "PSUseToExportFieldsInManifest" rule for dev branch --- ScriptAnalyzerSettings.psd1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ScriptAnalyzerSettings.psd1 b/ScriptAnalyzerSettings.psd1 index b4dd6ca4..004d1ca9 100644 --- a/ScriptAnalyzerSettings.psd1 +++ b/ScriptAnalyzerSettings.psd1 @@ -18,7 +18,8 @@ # Use ExcludeRules when you want to run most of the default set of rules except # for a few rules you wish to "exclude". Note: if a rule is in both IncludeRules # and ExcludeRules, the rule will be excluded. - #ExcludeRules = @('PSAvoidUsingWriteHost') + # ExcludeRules = @('PSAvoidUsingWriteHost') + ExcludeRules = @('PSUseToExportFieldsInManifest') # You can use the following entry to supply parameters to rules that take parameters. # For instance, the PSAvoidUsingCmdletAliases rule takes a whitelist for aliases you From 80d9c20f24b64b3856a1f95183e3ad7bb68773a0 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 21 Jun 2017 13:31:54 +0200 Subject: [PATCH 091/102] Remove unused valiables --- PSJira/Public/Add-JiraGroupMember.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/PSJira/Public/Add-JiraGroupMember.ps1 b/PSJira/Public/Add-JiraGroupMember.ps1 index cd6630cd..e731a3e7 100644 --- a/PSJira/Public/Add-JiraGroupMember.ps1 +++ b/PSJira/Public/Add-JiraGroupMember.ps1 @@ -136,9 +136,7 @@ function Add-JiraGroupMember if ($PassThru) { Write-Debug "[Add-JiraGroupMember] -PassThru specified. Obtaining a final reference to group [$g]" - $groupObjNew = Get-JiraGroup -InputObject $g -Credential $Credential - Write-Debug "[Add-JiraGroupMember] Outputting group [$groupObjNew]" - Write-Output $groupObjNew + $result | ConvertTo-JiraGroup } } else From 675e77ebd62df81c4daa2e84fb3eae3503944c74 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 22 Jun 2017 08:20:36 +0200 Subject: [PATCH 092/102] Fix $null comparison --- PSJira/Internal/Invoke-JiraMethod.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSJira/Internal/Invoke-JiraMethod.ps1 b/PSJira/Internal/Invoke-JiraMethod.ps1 index c97ecbb5..e995d1a7 100644 --- a/PSJira/Internal/Invoke-JiraMethod.ps1 +++ b/PSJira/Internal/Invoke-JiraMethod.ps1 @@ -110,7 +110,7 @@ function Invoke-JiraMethod } } - if ($null -ne $result.errors) + if ($result.errors) { Write-Debug "[Invoke-JiraMethod] An error response was received from JIRA; resolving" Resolve-JiraError $result -WriteError From a84839536df987283a464608ddb4c74730c08f95 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 22 Jun 2017 08:22:08 +0200 Subject: [PATCH 093/102] Update Unit Test to use common resources --- Tests/Invoke-JiraMethod.Tests.ps1 | 53 ++++++------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/Tests/Invoke-JiraMethod.Tests.ps1 b/Tests/Invoke-JiraMethod.Tests.ps1 index 810d01e3..3d633371 100644 --- a/Tests/Invoke-JiraMethod.Tests.ps1 +++ b/Tests/Invoke-JiraMethod.Tests.ps1 @@ -7,40 +7,14 @@ param() InModuleScope PSJira { - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] $SuppressImportModule = $true . $PSScriptRoot\Shared.ps1 - $validMethods = @('Get','Post','Put','Delete') + $validMethods = @('Get', 'Post', 'Put', 'Delete') Describe "Invoke-JiraMethod" { - ## Helper functions - - if ($ShowDebugText) - { - Mock "Write-Debug" { - Write-Host " [DEBUG] $Message" -ForegroundColor Yellow - } - } - - function defParam($command, $name) - { - It "Has a -$name parameter" { - $command.Parameters.Item($name) | Should Not BeNullOrEmpty - } - } - - function ShowMockInfo($functionName, [String[]] $params) { - if ($ShowMockData) - { - Write-Host " Mocked $functionName" -ForegroundColor Cyan - foreach ($p in $params) { - Write-Host " [$p] $(Get-Variable -Name $p -ValueOnly)" -ForegroundColor Cyan - } - } - } - Context "Sanity checking" { $command = Get-Command -Name Invoke-JiraMethod @@ -60,21 +34,14 @@ InModuleScope PSJira { $testUri = 'http://example.com' $testUsername = 'testUsername' $testPassword = 'password123' - $testCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUsername,(ConvertTo-SecureString -AsPlainText -Force $testPassword) + $testCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUsername, (ConvertTo-SecureString -AsPlainText -Force $testPassword) Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri','Method' - # if ($ShowMockData) - # { - # Write-Host " Mocked Invoke-WebRequest" -ForegroundColor Cyan - # Write-Host " [Uri] $Uri" -ForegroundColor Cyan - # Write-Host " [Method] $Method" -ForegroundColor Cyan - # } + ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' } It "Correctly performs all necessary HTTP method requests [$($validMethods -join ',')] to a provided URI" { - foreach ($method in $validMethods) - { + foreach ($method in $validMethods) { { Invoke-JiraMethod -Method $method -URI $testUri } | Should Not Throw Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Method -eq $method -and $Uri -eq $testUri} -Scope It } @@ -453,7 +420,7 @@ InModuleScope PSJira { It "Outputs an object representation of JSON returned from JIRA" { Mock Invoke-WebRequest -ParameterFilter {$Method -eq 'Get' -and $Uri -eq $validTestUri} { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri','Method' + ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' Write-Output [PSCustomObject] @{ 'Content' = $validRestResult } @@ -471,11 +438,11 @@ InModuleScope PSJira { Context "Output handling - no content returned (HTTP 204)" { Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri','Method' + ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' Write-Output [PSCustomObject] @{ 'StatusCode' = 204 - 'Content' = $null + 'Content' = $null } } Mock ConvertFrom-Json2 { @@ -493,7 +460,7 @@ InModuleScope PSJira { $invalidRestResult = '{"errorMessages":["Issue Does Not Exist"],"errors":{}}'; Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri','Method' + ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' Write-Output [PSCustomObject] @{ 'StatusCode' = 400 'Content' = $invalidRestResult @@ -505,7 +472,7 @@ InModuleScope PSJira { } It "Uses Resolve-JiraError to parse any JIRA error messages returned" { - { Invoke-JiraMethod -Method Get -URI $invalidTestUri } | Should Not Throw + { Invoke-JiraMethod -Method Get -URI $invalidTestUri } | Should Not Throw Assert-MockCalled -CommandName Resolve-JiraError -Exactly -Times 1 -Scope It } } From c22dc4e1c38c4acae9ac20879c3df81be4ab1910 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 22 Jun 2017 08:22:34 +0200 Subject: [PATCH 094/102] Add common resources for Unit Tests --- Tests/Shared.ps1 | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/Tests/Shared.ps1 b/Tests/Shared.ps1 index 5cb587c9..35041e34 100644 --- a/Tests/Shared.ps1 +++ b/Tests/Shared.ps1 @@ -20,21 +20,31 @@ if (-not (Get-Module -Name $ModuleName -ErrorAction SilentlyContinue) -or (!$Sup $SuppressImportModule = $true } -[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='ShowMockData')] +[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'ShowMockData')] $ShowMockData = $false -[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='ShowDebugText')] +[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'ShowDebugText')] $ShowDebugText = $false -function defProp($obj, $propName, $propValue) -{ +function defProp($obj, $propName, $propValue) { It "Defines the '$propName' property" { $obj.$propName | Should Be $propValue } } -function defParam($command, $name) -{ +function hasProp($obj, $propName) { + It "Defines the '$propName' property" { + $obj | Get-Member -MemberType *Property -Name $propName | Should Not BeNullOrEmpty + } +} + +function hasNotProp($obj, $propName) { + It "Defines the '$propName' property" { + $obj | Get-Member -MemberType *Property -Name $propName | Should BeNullOrEmpty + } +} + +function defParam($command, $name) { It "Has a -$name parameter" { $command.Parameters.Item($name) | Should Not BeNullOrEmpty } @@ -52,19 +62,37 @@ function checkType($obj, $typeName) { $o.PSObject.TypeNames[0] | Should Be $typeName } +function castsToString($obj) { + if ($obj -is [System.Array]) { + $o = $obj[0] + } + else { + $o = $obj + } + + $o.ToString() | Should Not BeNullOrEmpty +} + function checkPsType($obj, $typeName) { It "Uses output type of '$typeName'" { checkType $obj $typeName } + It "Can cast to string" { + castsToString($obj) + } } -function ShowMockInfo($functionName, [String[]] $params) -{ - if ($ShowMockData) - { +function ShowMockInfo($functionName, [String[]] $params) { + if ($ShowMockData) { Write-Host " Mocked $functionName" -ForegroundColor Cyan foreach ($p in $params) { Write-Host " [$p] $(Get-Variable -Name $p -ValueOnly)" -ForegroundColor Cyan } } } + +if ($ShowDebugText) { + Mock "Write-Debug" { + Write-Host " [DEBUG] $Message" -ForegroundColor Yellow + } +} From 0c74d321a73e6c0d3f5472cb878904ddc59ea3eb Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 23 Jun 2017 09:08:38 +0200 Subject: [PATCH 095/102] Improve testing for response with errors --- PSJira/Internal/Invoke-JiraMethod.ps1 | 64 ++++++++++++--------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/PSJira/Internal/Invoke-JiraMethod.ps1 b/PSJira/Internal/Invoke-JiraMethod.ps1 index e995d1a7..ad147277 100644 --- a/PSJira/Internal/Invoke-JiraMethod.ps1 +++ b/PSJira/Internal/Invoke-JiraMethod.ps1 @@ -1,11 +1,10 @@ -function Invoke-JiraMethod -{ +function Invoke-JiraMethod { #Requires -Version 3 - [CmdletBinding(DefaultParameterSetName='UseCredential')] + [CmdletBinding(DefaultParameterSetName = 'UseCredential')] param ( [Parameter(Mandatory = $true)] - [ValidateSet('Get','Post','Put','Delete')] + [ValidateSet('Get', 'Post', 'Put', 'Delete')] [String] $Method, [Parameter(Mandatory = $true)] @@ -14,13 +13,13 @@ function Invoke-JiraMethod [ValidateNotNullOrEmpty()] [String] $Body, - [Parameter(ParameterSetName='UseCredential', - Mandatory = $false)] + [Parameter(ParameterSetName = 'UseCredential', + Mandatory = $false)] [System.Management.Automation.PSCredential] $Credential -# [Parameter(ParameterSetName='UseSession', -# Mandatory = $true)] -# [Object] $Session + # [Parameter(ParameterSetName='UseSession', + # Mandatory = $true)] + # [Object] $Session ) # load DefaultParameters for Invoke-WebRequest @@ -32,21 +31,21 @@ function Invoke-JiraMethod 'Content-Type' = 'application/json; charset=utf-8'; } - if ($Credential) - { + if ($Credential) { Write-Debug "[Invoke-JiraMethod] Using HTTP Basic authentication with provided credentials for $($Credential.UserName)" [String] $Username = $Credential.UserName $token = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("${Username}:$($Credential.GetNetworkCredential().Password)")) $headers.Add('Authorization', "Basic $token") Write-Verbose "Using HTTP Basic authentication with username $($Credential.UserName)" - } else { + } + else { Write-Debug "[Invoke-JiraMethod] Credentials were not provided. Checking for a saved session" $session = Get-JiraSession - if ($session) - { + if ($session) { Write-Debug "[Invoke-JiraMethod] A session was found; using saved session (Username=[$($session.Username)], JSessionID=[$($session.JSessionID)])" Write-Verbose "Using saved Web session with username $($session.Username)" - } else { + } + else { $session = $null Write-Debug "[Invoke-JiraMethod] No saved session was found; using anonymous access" } @@ -60,22 +59,19 @@ function Invoke-JiraMethod ErrorAction = 'SilentlyContinue' } - if ($Body) - { + if ($Body) { # http://stackoverflow.com/questions/15290185/invoke-webrequest-issue-with-special-characters-in-json $cleanBody = [System.Text.Encoding]::UTF8.GetBytes($Body) $iwrSplat.Add('Body', $cleanBody) } - if ($Session) - { + if ($Session) { $iwrSplat.Add('WebSession', $session.WebSession) } # We don't need to worry about $Credential, because it's part of the headers being sent to Jira - try - { + try { Write-Debug "[Invoke-JiraMethod] Invoking JIRA method $Method to URI $URI" $webResponse = Invoke-WebRequest @iwrSplat @@ -85,12 +81,10 @@ function Invoke-JiraMethod $webResponse = $_.Exception.Response } - if ($webResponse) - { + if ($webResponse) { Write-Debug "[Invoke-JiraMethod] Status code: $($webResponse.StatusCode)" - if ($webResponse.StatusCode.value__ -gt 399) - { + if ($webResponse.StatusCode.value__ -gt 399) { Write-Warning "JIRA returned HTTP error $($webResponse.StatusCode.value__) - $($webResponse.StatusCode)" # Retrieve body of HTTP response - this contains more useful information about exactly why the error @@ -100,27 +94,27 @@ function Invoke-JiraMethod $readStream.Close() Write-Debug "[Invoke-JiraMethod] Retrieved body of HTTP response for more information about the error (`$responseBody)" $result = ConvertFrom-Json2 -InputObject $responseBody - } else { - if ($webResponse.Content) - { + } + else { + if ($webResponse.Content) { Write-Debug "[Invoke-JiraMethod] Converting body of response from JSON" $result = ConvertFrom-Json2 -InputObject $webResponse.Content - } else { + } + else { Write-Debug "[Invoke-JiraMethod] No content was returned from JIRA." } } - if ($result.errors) - { + if (Get-Member -Name "Errors" -InputObject $result -ErrorAction SilentlyContinue) { Write-Debug "[Invoke-JiraMethod] An error response was received from JIRA; resolving" Resolve-JiraError $result -WriteError - } else { + } + else { Write-Debug "[Invoke-JiraMethod] Outputting results from JIRA" Write-Output $result } - } else { + } + else { Write-Debug "[Invoke-JiraMethod] No Web result object was returned from JIRA. This is unusual!" } } - - From ee91ccf38f3d45ec036b20d1853fc6637f7a6e6b Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 23 Jun 2017 09:37:53 +0200 Subject: [PATCH 096/102] Add method ToString() to objects --- PSJira/Internal/ConvertTo-JiraIssueLink.ps1 | 6 +++++- PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 | 6 +++++- PSJira/Internal/ConvertTo-JiraPriority.ps1 | 5 +++++ PSJira/Internal/ConvertTo-JiraStatus.ps1 | 6 +++++- Tests/ConvertTo-JiraIssueLink.Tests.ps1 | 2 +- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 index e92be588..9b7980a6 100644 --- a/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 @@ -5,7 +5,7 @@ function ConvertTo-JiraIssueLink { Position = 0, ValueFromPipeline = $true)] [PSObject[]] $InputObject, - + [Switch] $ReturnError ) @@ -34,6 +34,10 @@ function ConvertTo-JiraIssueLink { $result = New-Object -TypeName PSObject -Property $props $result.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.ID)" + } + Write-Output $result } } diff --git a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 b/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 index bf316df8..fbfcc25f 100644 --- a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 +++ b/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 @@ -5,7 +5,7 @@ function ConvertTo-JiraIssueLinkType { Position = 0, ValueFromPipeline = $true)] [PSObject[]] $InputObject, - + [Switch] $ReturnError ) @@ -35,6 +35,10 @@ function ConvertTo-JiraIssueLinkType { $result = New-Object -TypeName PSObject -Property $props $result.PSObject.TypeNames.Insert(0, 'PSJira.IssueLinkType') + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Name)" + } + Write-Output $result } } diff --git a/PSJira/Internal/ConvertTo-JiraPriority.ps1 b/PSJira/Internal/ConvertTo-JiraPriority.ps1 index 79b93783..c8595bf1 100644 --- a/PSJira/Internal/ConvertTo-JiraPriority.ps1 +++ b/PSJira/Internal/ConvertTo-JiraPriority.ps1 @@ -55,6 +55,11 @@ function ConvertTo-JiraPriority # Write-Debug "[ConvertTo-JiraPriority] Inserting type name information" $result.PSObject.TypeNames.Insert(0, 'PSJira.Priority') + # Write-Debug "[ConvertTo-JiraPriority] Inserting custom toString() method" + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Name)" + } + # Write-Debug "[ConvertTo-JiraPriority] Outputting object" Write-Output $result } diff --git a/PSJira/Internal/ConvertTo-JiraStatus.ps1 b/PSJira/Internal/ConvertTo-JiraStatus.ps1 index de20a043..752391b8 100644 --- a/PSJira/Internal/ConvertTo-JiraStatus.ps1 +++ b/PSJira/Internal/ConvertTo-JiraStatus.ps1 @@ -26,13 +26,17 @@ function ConvertTo-JiraStatus 'RestUrl' = $i.self; } - # Write-Debug "[ConvertTo-JiraStatus] Creating PSObject out of properties" $result = New-Object -TypeName PSObject -Property $props # Write-Debug "[ConvertTo-JiraStatus] Inserting type name information" $result.PSObject.TypeNames.Insert(0, 'PSJira.Status') + # Write-Debug "[ConvertTo-JiraStatus] Inserting custom toString() method" + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Name)" + } + # Write-Debug "[ConvertTo-JiraStatus] Outputting object" Write-Output $result } diff --git a/Tests/ConvertTo-JiraIssueLink.Tests.ps1 b/Tests/ConvertTo-JiraIssueLink.Tests.ps1 index 0e96a94c..2a27bbfd 100644 --- a/Tests/ConvertTo-JiraIssueLink.Tests.ps1 +++ b/Tests/ConvertTo-JiraIssueLink.Tests.ps1 @@ -38,7 +38,7 @@ InModuleScope PSJira { checkPsType $r 'PSJira.IssueLink' defProp $r 'Id' $issueLinkId - defProp $r 'Type' "@{OutwardText=composes; InwardText=is part of; Name=Composition; ID=10500; RestUrl=}" + defProp $r 'Type' "Composition" defProp $r 'InwardIssue' "[$issueKeyInward] " defProp $r 'OutwardIssue' "[$issueKeyOutward] " From 24ebea6aa9711ef0fb75b084e0beeaa8da0aef7d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 23 Jun 2017 09:38:18 +0200 Subject: [PATCH 097/102] Add support for ShouldProcess --- PSJira/Public/Remove-JiraIssueWatcher.ps1 | 37 +++++------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/PSJira/Public/Remove-JiraIssueWatcher.ps1 b/PSJira/Public/Remove-JiraIssueWatcher.ps1 index f43c3043..a949f45c 100644 --- a/PSJira/Public/Remove-JiraIssueWatcher.ps1 +++ b/PSJira/Public/Remove-JiraIssueWatcher.ps1 @@ -21,7 +21,7 @@ .NOTES This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $true)] param( # Watcher that should be removed from JIRA [Parameter(Mandatory = $true, @@ -49,39 +49,16 @@ process { -# Write-Debug "[Remove-JiraIssueWatcher] Checking Issue parameter" -# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') -# { -# Write-Debug "[Remove-JiraIssueWatcher] Issue parameter is a PSJira.Issue object" -# $issueObj = $Issue -# } else { -# $issueKey = $Issue.ToString() -# Write-Debug "[Remove-JiraIssueWatcher] Issue key is assumed to be [$issueKey] via ToString()" -# Write-Verbose "Searching for issue [$issueKey]" -# try -# { -# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential -# } catch { -# $err = $_ -# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' -# throw $err -# } -# } -# -# if (-not $issueObj) -# { -# Write-Debug "[Remove-JiraIssueWatcher] No Jira issues were found for parameter [$Issue]. An exception will be thrown." -# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" -# } - Write-Debug "[Remove-JiraIssueWatcher] Obtaining a reference to Jira issue [$Issue]" $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential - foreach ($w in $Watcher) { - $url = "$($issueObj.RestURL)/watchers?username=$w" + foreach ($username in $Watcher) { + $url = "$($issueObj.RestURL)/watchers?username=$username" - Write-Debug "[Remove-JiraIssueWatcher] Preparing for blastoff!" - $rawResult = Invoke-JiraMethod -Method Delete -URI $url -Credential $Credential + if ($PSCmdlet.ShouldProcess($username, "Removing a watcher of issue [$($Issue.Key)]")) { + Write-Debug "[Remove-JiraIssueWatcher] Preparing for blastoff!" + Invoke-JiraMethod -Method Delete -URI $url -Credential $Credential + } } } From 95a8a1b6ae005970a857b9aed5c1c7bb164bc120 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 23 Jun 2017 09:38:56 +0200 Subject: [PATCH 098/102] Remove unused variable --- PSJira/Public/Add-JiraIssueWatcher.ps1 | 27 +------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/PSJira/Public/Add-JiraIssueWatcher.ps1 b/PSJira/Public/Add-JiraIssueWatcher.ps1 index 12dedd5d..08c65665 100644 --- a/PSJira/Public/Add-JiraIssueWatcher.ps1 +++ b/PSJira/Public/Add-JiraIssueWatcher.ps1 @@ -49,31 +49,6 @@ process { -# Write-Debug "[Add-JiraIssueWatcher] Checking Issue parameter" -# if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') -# { -# Write-Debug "[Add-JiraIssueWatcher] Issue parameter is a PSJira.Issue object" -# $issueObj = $Issue -# } else { -# $issueKey = $Issue.ToString() -# Write-Debug "[Add-JiraIssueWatcher] Issue key is assumed to be [$issueKey] via ToString()" -# Write-Verbose "Searching for issue [$issueKey]" -# try -# { -# $issueObj = Get-JiraIssue -Key $issueKey -Credential $Credential -# } catch { -# $err = $_ -# Write-Debug 'Encountered an error searching for Jira issue. An exception will be thrown.' -# throw $err -# } -# } -# -# if (-not $issueObj) -# { -# Write-Debug "[Add-JiraIssueWatcher] No Jira issues were found for parameter [$Issue]. An exception will be thrown." -# throw "Unable to identify Jira issue [$Issue]. Does this issue exist?" -# } - Write-Debug "[Add-JiraIssueWatcher] Obtaining a reference to Jira issue [$Issue]" $issueObj = Get-JiraIssue -InputObject $Issue -Credential $Credential @@ -83,7 +58,7 @@ $body = """$w""" Write-Debug "[Add-JiraIssueWatcher] Preparing for blastoff!" - $rawResult = Invoke-JiraMethod -Method Post -URI $url -Body $body -Credential $Credential + Invoke-JiraMethod -Method Post -URI $url -Body $body -Credential $Credential } } From 0674873ce023b93848858403d9b66f10f099eb99 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 23 Jun 2017 10:09:43 +0200 Subject: [PATCH 099/102] Update relative Path for PSScriptAnalyzer --- Tests/PSJira.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/PSJira.Tests.ps1 b/Tests/PSJira.Tests.ps1 index 8978b783..9c650323 100644 --- a/Tests/PSJira.Tests.ps1 +++ b/Tests/PSJira.Tests.ps1 @@ -185,7 +185,7 @@ Describe "PSJira" { } Context 'PSScriptAnalyzer Rules' { - $analysis = Invoke-ScriptAnalyzer -Path .\PSJira -Recurse -Settings ".\ScriptAnalyzerSettings.psd1" -CustomRulePath "$PSScriptRoot\..\Rules\" -IncludeDefaultRules + $analysis = Invoke-ScriptAnalyzer -Path "$moduleRoot" -Recurse -Settings ".\ScriptAnalyzerSettings.psd1" $scriptAnalyzerRules = Get-ScriptAnalyzerRule forEach ($rule in $scriptAnalyzerRules) { From bbb4377b69aa6a726bd9c122fe28e2a0278ff68a Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 25 Jun 2017 16:41:50 +0200 Subject: [PATCH 100/102] Rename module in PRs since last major release --- .../Internal/ConvertTo-JiraIssueLink.ps1 | 98 ++++----- .../Internal/ConvertTo-JiraIssueLinkType.ps1 | 4 +- .../Internal/ConvertTo-JiraLink.ps1 | 2 +- .../Internal/ConvertTo-JiraWorklogitem.ps1 | 2 +- JiraPS/Internal/Invoke-JiraMethod.ps1 | 2 +- .../Public/Add-JiraIssueLink.ps1 | 204 ++++++++--------- .../Public/Add-JiraIssueWatcher.ps1 | 2 +- .../Public/Add-JiraIssueWorklog.ps1 | 8 +- JiraPS/Public/Get-JiraComponent.ps1 | 2 +- JiraPS/Public/Get-JiraIssueComment.ps1 | 2 +- .../Public/Get-JiraIssueLink.ps1 | 162 +++++++------- .../Public/Get-JiraIssueLinkType.ps1 | 2 +- JiraPS/Public/Get-JiraIssueType.ps1 | 4 +- .../Public/Get-JiraIssueWatcher.ps1 | 6 +- JiraPS/Public/Get-JiraPriority.ps1 | 4 +- .../Public/Get-JiraRemoteLink.ps1 | 170 +++++++------- .../Public/Remove-JiraIssueLink.ps1 | 158 ++++++------- .../Public/Remove-JiraIssueWatcher.ps1 | 2 +- .../Public/Remove-JiraRemoteLink.ps1 | 208 +++++++++--------- JiraPS/Public/Remove-JiraSession.ps1 | 6 +- Tests/Add-JiraIssueLink.Tests.ps1 | 8 +- Tests/Add-JiraIssueWatcher.Tests.ps1 | 18 +- Tests/Add-JiraIssueWorklog.Tests.ps1 | 20 +- Tests/ConvertTo-JiraIssueLink.Tests.ps1 | 4 +- Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 | 6 +- Tests/ConvertTo-JiraLink.Tests.ps1 | 4 +- Tests/ConvertTo-JiraWorklogitem.Tests.ps1 | 6 +- Tests/Get-JiraIssueLink.Tests.ps1 | 12 +- Tests/Get-JiraIssueLinkType.Tests.ps1 | 12 +- Tests/Get-JiraIssueWatcher.Tests.ps1 | 18 +- Tests/Get-JiraRemoteLink.Tests.ps1 | 10 +- Tests/Invoke-JiraIssueTransition.Tests.ps1 | 12 +- Tests/PSJira.Help.Tests.ps1 | 2 +- Tests/Remove-JiraIssueLink.Tests.ps1 | 22 +- Tests/Remove-JiraIssueWatcher.Tests.ps1 | 18 +- Tests/Remove-JiraRemoteLink.Tests.ps1 | 12 +- build/build.settings.ps1 | 4 +- 37 files changed, 618 insertions(+), 618 deletions(-) rename {PSJira => JiraPS}/Internal/ConvertTo-JiraIssueLink.ps1 (88%) rename {PSJira => JiraPS}/Internal/ConvertTo-JiraIssueLinkType.ps1 (90%) rename {PSJira => JiraPS}/Internal/ConvertTo-JiraLink.ps1 (97%) rename {PSJira => JiraPS}/Internal/ConvertTo-JiraWorklogitem.ps1 (97%) rename {PSJira => JiraPS}/Public/Add-JiraIssueLink.ps1 (90%) rename {PSJira => JiraPS}/Public/Add-JiraIssueWatcher.ps1 (97%) rename {PSJira => JiraPS}/Public/Add-JiraIssueWorklog.ps1 (96%) rename {PSJira => JiraPS}/Public/Get-JiraIssueLink.ps1 (93%) rename {PSJira => JiraPS}/Public/Get-JiraIssueLinkType.ps1 (98%) rename {PSJira => JiraPS}/Public/Get-JiraIssueWatcher.ps1 (93%) rename {PSJira => JiraPS}/Public/Get-JiraRemoteLink.ps1 (94%) rename {PSJira => JiraPS}/Public/Remove-JiraIssueLink.ps1 (86%) rename {PSJira => JiraPS}/Public/Remove-JiraIssueWatcher.ps1 (97%) rename {PSJira => JiraPS}/Public/Remove-JiraRemoteLink.ps1 (95%) diff --git a/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 b/JiraPS/Internal/ConvertTo-JiraIssueLink.ps1 similarity index 88% rename from PSJira/Internal/ConvertTo-JiraIssueLink.ps1 rename to JiraPS/Internal/ConvertTo-JiraIssueLink.ps1 index 9b7980a6..80ce264d 100644 --- a/PSJira/Internal/ConvertTo-JiraIssueLink.ps1 +++ b/JiraPS/Internal/ConvertTo-JiraIssueLink.ps1 @@ -1,49 +1,49 @@ -function ConvertTo-JiraIssueLink { - [CmdletBinding()] - param( - [Parameter(Mandatory = $true, - Position = 0, - ValueFromPipeline = $true)] - [PSObject[]] $InputObject, - - [Switch] $ReturnError - ) - - process { - foreach ($i in $InputObject) { - if ($i.errorMessages) { - if ($ReturnError) { - $props = @{ - 'ErrorMessages' = $i.errorMessages; - } - - $result = New-Object -TypeName PSObject -Property $props - $result.PSObject.TypeNames.Insert(0, 'PSJira.Error') - - Write-Output $result - } - } - else { - $props = @{ - 'ID' = $i.id - 'Type' = (ConvertTo-JiraIssueLinkType $i.type) - } - if ($i.inwardIssue) { $props['InwardIssue'] = (ConvertTo-JiraIssue $i.inwardIssue) } - if ($i.outwardIssue) { $props['OutwardIssue'] = (ConvertTo-JiraIssue $i.outwardIssue) } - - $result = New-Object -TypeName PSObject -Property $props - $result.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') - - $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { - Write-Output "$($this.ID)" - } - - Write-Output $result - } - } - } - - end - { - } -} +function ConvertTo-JiraIssueLink { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject, + + [Switch] $ReturnError + ) + + process { + foreach ($i in $InputObject) { + if ($i.errorMessages) { + if ($ReturnError) { + $props = @{ + 'ErrorMessages' = $i.errorMessages; + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'JiraPS.Error') + + Write-Output $result + } + } + else { + $props = @{ + 'ID' = $i.id + 'Type' = (ConvertTo-JiraIssueLinkType $i.type) + } + if ($i.inwardIssue) { $props['InwardIssue'] = (ConvertTo-JiraIssue $i.inwardIssue) } + if ($i.outwardIssue) { $props['OutwardIssue'] = (ConvertTo-JiraIssue $i.outwardIssue) } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'JiraPS.IssueLink') + + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.ID)" + } + + Write-Output $result + } + } + } + + end + { + } +} diff --git a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 b/JiraPS/Internal/ConvertTo-JiraIssueLinkType.ps1 similarity index 90% rename from PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 rename to JiraPS/Internal/ConvertTo-JiraIssueLinkType.ps1 index fbfcc25f..e738b0b4 100644 --- a/PSJira/Internal/ConvertTo-JiraIssueLinkType.ps1 +++ b/JiraPS/Internal/ConvertTo-JiraIssueLinkType.ps1 @@ -18,7 +18,7 @@ function ConvertTo-JiraIssueLinkType { } $result = New-Object -TypeName PSObject -Property $props - $result.PSObject.TypeNames.Insert(0, 'PSJira.Error') + $result.PSObject.TypeNames.Insert(0, 'JiraPS.Error') Write-Output $result } @@ -33,7 +33,7 @@ function ConvertTo-JiraIssueLinkType { } $result = New-Object -TypeName PSObject -Property $props - $result.PSObject.TypeNames.Insert(0, 'PSJira.IssueLinkType') + $result.PSObject.TypeNames.Insert(0, 'JiraPS.IssueLinkType') $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { Write-Output "$($this.Name)" diff --git a/PSJira/Internal/ConvertTo-JiraLink.ps1 b/JiraPS/Internal/ConvertTo-JiraLink.ps1 similarity index 97% rename from PSJira/Internal/ConvertTo-JiraLink.ps1 rename to JiraPS/Internal/ConvertTo-JiraLink.ps1 index 97c52419..09cc67ae 100644 --- a/PSJira/Internal/ConvertTo-JiraLink.ps1 +++ b/JiraPS/Internal/ConvertTo-JiraLink.ps1 @@ -67,7 +67,7 @@ function ConvertTo-JiraLink $result = New-Object -TypeName PSObject -Property $props # Write-Debug "[ConvertTo-JiraLink] Inserting type name information" - $result.PSObject.TypeNames.Insert(0, 'PSJira.Link') + $result.PSObject.TypeNames.Insert(0, 'JiraPS.Link') # Write-Debug "[ConvertTo-JiraLink] Inserting custom toString() method" $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { diff --git a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 b/JiraPS/Internal/ConvertTo-JiraWorklogitem.ps1 similarity index 97% rename from PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 rename to JiraPS/Internal/ConvertTo-JiraWorklogitem.ps1 index 62d45521..60e1ec4b 100644 --- a/PSJira/Internal/ConvertTo-JiraWorklogitem.ps1 +++ b/JiraPS/Internal/ConvertTo-JiraWorklogitem.ps1 @@ -71,7 +71,7 @@ function ConvertTo-JiraWorklogItem $result = New-Object -TypeName PSObject -Property $props # Write-Debug "[ConvertTo-JiraWorklogitem] Inserting type name information" - $result.PSObject.TypeNames.Insert(0, 'PSJira.Worklogitem') + $result.PSObject.TypeNames.Insert(0, 'JiraPS.Worklogitem') # Write-Debug "[ConvertTo-JiraWorklogitem] Inserting custom toString() method" $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { diff --git a/JiraPS/Internal/Invoke-JiraMethod.ps1 b/JiraPS/Internal/Invoke-JiraMethod.ps1 index 39a41c57..04cbf108 100644 --- a/JiraPS/Internal/Invoke-JiraMethod.ps1 +++ b/JiraPS/Internal/Invoke-JiraMethod.ps1 @@ -24,7 +24,7 @@ function Invoke-JiraMethod { # load DefaultParameters for Invoke-WebRequest # as the global PSDefaultParameterValues is not used - # TODO: find out why PSJira doesn't need this + # TODO: find out why JiraPS doesn't need this $PSDefaultParameterValues = $global:PSDefaultParameterValues $headers = @{} diff --git a/PSJira/Public/Add-JiraIssueLink.ps1 b/JiraPS/Public/Add-JiraIssueLink.ps1 similarity index 90% rename from PSJira/Public/Add-JiraIssueLink.ps1 rename to JiraPS/Public/Add-JiraIssueLink.ps1 index e3866455..cd3c42b8 100644 --- a/PSJira/Public/Add-JiraIssueLink.ps1 +++ b/JiraPS/Public/Add-JiraIssueLink.ps1 @@ -1,102 +1,102 @@ -function Add-JiraIssueLink { - <# - .Synopsis - Adds a link between two Issues on Jira - .DESCRIPTION - Creates a new link of the specified type between two Issue. - .EXAMPLE - $link = [PSCustomObject]@{ - outwardIssue = [PSCustomObject]@{key = "TEST-10"} - type = [PSCustomObject]@{name = "Composition"} - } - Add-JiraIssueLink -Issue TEST-01 -IssueLink $link - Creates a link "is part of" between TEST-01 and TEST-10 - .INPUTS - [PSJira.Issue[]] The JIRA issue that should be linked - [PSJira.IssueLink[]] The JIRA issue link that should be used - #> - [CmdletBinding()] - param( - # Issue key or PSJira.Issue object returned from Get-JiraIssue - [Parameter( - Position = 0, - Mandatory = $true, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true - )] - [Alias('Key')] - [Object[]] $Issue, - - # Issue Link to be created. - [Parameter(Mandatory = $true)] - [Object[]] $IssueLink, - - # Write a comment to the issue - [String] $Comment, - - # Credentials to use to connect to Jira - [Parameter(Mandatory = $false)] - [System.Management.Automation.PSCredential] $Credential<#, - - [Switch] $PassThru#> - ) - - begin { - Write-Debug "[Add-JiraIssueLink] Reading server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - - $issueLinkURL = "$($server)/rest/api/latest/issueLink" - } - - process { - # Validate IssueLink object - $objectProperties = $IssueLink | Get-Member -MemberType *Property - if (-not(($objectProperties.Name -contains "type") -and (($objectProperties.Name -contains "outwardIssue") -or ($objectProperties.Name -contains "inwardIssue")))) { - $message = "The IssueLink provided does not contain the information needed." - $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message - Throw $exception - } - - # Validate input object from Pipeline - if (($_) -and ($_.PSObject.TypeNames[0] -ne "PSJira.Issue")) { - $message = "Wrong object type provided for Issue. Only PSJira.Issue is accepted" - $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message - Throw $exception - } - - foreach ($i in $Issue) { - Write-Debug "[Add-JiraIssueLink] Obtaining reference to issue" - $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential - - foreach ($link in $IssueLink) { - if ($link.inwardIssue) { - $inwardIssue = [PSCustomObject]@{key = $link.inwardIssue.key} - } - else { - $inwardIssue = [PSCustomObject]@{key = $issueObj.key} - } - - if ($link.outwardIssue) { - $outwardIssue = [PSCustomObject]@{key = $link.outwardIssue.key} - } - else { - $outwardIssue = [PSCustomObject]@{key = $issueObj.key} - } - - $body = [PSCustomObject]@{ - type = [PSCustomObject]@{name = $link.type.name} - inwardIssue = $inwardIssue - outwardIssue = $outwardIssue - } - if ($Comment) {$body["comment"] = [PSCustomObject]@{body = $Comment}} - $json = ConvertTo-Json $body - - $null = Invoke-JiraMethod -Method POST -URI $issueLinkURL -Body $json -Credential $Credential - } - } - } - - end { - Write-Debug "[Add-JiraIssueLink] Complete" - } -} +function Add-JiraIssueLink { + <# + .Synopsis + Adds a link between two Issues on Jira + .DESCRIPTION + Creates a new link of the specified type between two Issue. + .EXAMPLE + $link = [PSCustomObject]@{ + outwardIssue = [PSCustomObject]@{key = "TEST-10"} + type = [PSCustomObject]@{name = "Composition"} + } + Add-JiraIssueLink -Issue TEST-01 -IssueLink $link + Creates a link "is part of" between TEST-01 and TEST-10 + .INPUTS + [JiraPS.Issue[]] The JIRA issue that should be linked + [JiraPS.IssueLink[]] The JIRA issue link that should be used + #> + [CmdletBinding()] + param( + # Issue key or JiraPS.Issue object returned from Get-JiraIssue + [Parameter( + Position = 0, + Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('Key')] + [Object[]] $Issue, + + # Issue Link to be created. + [Parameter(Mandatory = $true)] + [Object[]] $IssueLink, + + # Write a comment to the issue + [String] $Comment, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential<#, + + [Switch] $PassThru#> + ) + + begin { + Write-Debug "[Add-JiraIssueLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + $issueLinkURL = "$($server)/rest/api/latest/issueLink" + } + + process { + # Validate IssueLink object + $objectProperties = $IssueLink | Get-Member -MemberType *Property + if (-not(($objectProperties.Name -contains "type") -and (($objectProperties.Name -contains "outwardIssue") -or ($objectProperties.Name -contains "inwardIssue")))) { + $message = "The IssueLink provided does not contain the information needed." + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + # Validate input object from Pipeline + if (($_) -and ($_.PSObject.TypeNames[0] -ne "JiraPS.Issue")) { + $message = "Wrong object type provided for Issue. Only JiraPS.Issue is accepted" + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + foreach ($i in $Issue) { + Write-Debug "[Add-JiraIssueLink] Obtaining reference to issue" + $issueObj = Get-JiraIssue -InputObject $i -Credential $Credential + + foreach ($link in $IssueLink) { + if ($link.inwardIssue) { + $inwardIssue = [PSCustomObject]@{key = $link.inwardIssue.key} + } + else { + $inwardIssue = [PSCustomObject]@{key = $issueObj.key} + } + + if ($link.outwardIssue) { + $outwardIssue = [PSCustomObject]@{key = $link.outwardIssue.key} + } + else { + $outwardIssue = [PSCustomObject]@{key = $issueObj.key} + } + + $body = [PSCustomObject]@{ + type = [PSCustomObject]@{name = $link.type.name} + inwardIssue = $inwardIssue + outwardIssue = $outwardIssue + } + if ($Comment) {$body["comment"] = [PSCustomObject]@{body = $Comment}} + $json = ConvertTo-Json $body + + $null = Invoke-JiraMethod -Method POST -URI $issueLinkURL -Body $json -Credential $Credential + } + } + } + + end { + Write-Debug "[Add-JiraIssueLink] Complete" + } +} diff --git a/PSJira/Public/Add-JiraIssueWatcher.ps1 b/JiraPS/Public/Add-JiraIssueWatcher.ps1 similarity index 97% rename from PSJira/Public/Add-JiraIssueWatcher.ps1 rename to JiraPS/Public/Add-JiraIssueWatcher.ps1 index 08c65665..8fc33e12 100644 --- a/PSJira/Public/Add-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Add-JiraIssueWatcher.ps1 @@ -15,7 +15,7 @@ Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Add-JiraIssueWatcher "fred" } This example illustrates adding watcher on all projects which match a given JQL query. It would be best to validate the query first to make sure the query returns the expected issues! .INPUTS - This function can accept PSJira.Issue objects via pipeline. + This function can accept JiraPS.Issue objects via pipeline. .OUTPUTS This function does not provide output. .NOTES diff --git a/PSJira/Public/Add-JiraIssueWorklog.ps1 b/JiraPS/Public/Add-JiraIssueWorklog.ps1 similarity index 96% rename from PSJira/Public/Add-JiraIssueWorklog.ps1 rename to JiraPS/Public/Add-JiraIssueWorklog.ps1 index b8c8eab3..8644b7f7 100644 --- a/PSJira/Public/Add-JiraIssueWorklog.ps1 +++ b/JiraPS/Public/Add-JiraIssueWorklog.ps1 @@ -19,9 +19,9 @@ function Add-JiraIssueWorklog Add-JiraIssueWorklog $c -Issue TEST-003 -TimeSpent 60 -DateStarted (Get-Date) This example illustrates adding a comment based on other logic to a JIRA issue. Note the use of Format-Jira to convert the output of Get-Process into a format that is easily read by users. .INPUTS - This function can accept PSJira.Issue objects via pipeline. + This function can accept JiraPS.Issue objects via pipeline. .OUTPUTS - This function outputs the PSJira.Worklogitem object created. + This function outputs the JiraPS.Worklogitem object created. .NOTES This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> @@ -72,9 +72,9 @@ function Add-JiraIssueWorklog process { Write-Debug "[Add-JiraIssueWorklog] Checking Issue parameter" - if ($Issue.PSObject.TypeNames[0] -eq 'PSJira.Issue') + if ($Issue.PSObject.TypeNames[0] -eq 'JiraPS.Issue') { - Write-Debug "[Add-JiraIssueWorklog] Issue parameter is a PSJira.Issue object" + Write-Debug "[Add-JiraIssueWorklog] Issue parameter is a JiraPS.Issue object" $issueObj = $Issue } else { $issueKey = $Issue.ToString() diff --git a/JiraPS/Public/Get-JiraComponent.ps1 b/JiraPS/Public/Get-JiraComponent.ps1 index 209309bc..b3ade152 100644 --- a/JiraPS/Public/Get-JiraComponent.ps1 +++ b/JiraPS/Public/Get-JiraComponent.ps1 @@ -67,7 +67,7 @@ function Get-JiraComponent { if ($Project) { - if ($Project.PSObject.TypeNames[0] -eq 'PSJira.Project') + if ($Project.PSObject.TypeNames[0] -eq 'JiraPS.Project') { $ComponentId = @($Project.Components | Select-Object -ExpandProperty id) } diff --git a/JiraPS/Public/Get-JiraIssueComment.ps1 b/JiraPS/Public/Get-JiraIssueComment.ps1 index b3a8ee21..2354af51 100644 --- a/JiraPS/Public/Get-JiraIssueComment.ps1 +++ b/JiraPS/Public/Get-JiraIssueComment.ps1 @@ -21,7 +21,7 @@ function Get-JiraIssueComment [CmdletBinding()] param( # JIRA issue to check for comments. - # Can be a PSJira.Issue object, issue key, or internal issue ID. + # Can be a JiraPS.Issue object, issue key, or internal issue ID. [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, diff --git a/PSJira/Public/Get-JiraIssueLink.ps1 b/JiraPS/Public/Get-JiraIssueLink.ps1 similarity index 93% rename from PSJira/Public/Get-JiraIssueLink.ps1 rename to JiraPS/Public/Get-JiraIssueLink.ps1 index f83d2fac..b8474678 100644 --- a/PSJira/Public/Get-JiraIssueLink.ps1 +++ b/JiraPS/Public/Get-JiraIssueLink.ps1 @@ -1,81 +1,81 @@ -function Get-JiraIssueLink { - <# - .Synopsis - Returns a specific issueLink from Jira - .DESCRIPTION - This function returns information regarding a specified issueLink from Jira. - .EXAMPLE - Get-JiraIssueLink 10000 - Returns information about the IssueLink with ID 10000 - .EXAMPLE - Get-JiraIssueLink -IssueLink 10000 - Returns information about the IssueLink with ID 10000 - .EXAMPLE - (Get-JiraIssue TEST-01).issuelinks | Get-JiraIssueLink - Returns the information about all IssueLinks in issue TEST-01 - .INPUTS - [Int[]] issueLink ID - [PSCredential] Credentials to use to connect to Jira - .OUTPUTS - [PSJira.IssueLink] - #> - [CmdletBinding()] - param( - # The IssueLink ID to search - # - # Accepts input from pipeline when the object is of type PSJira.IssueLink - [Parameter( - Position = 0, - Mandatory = $true, - ValueFromPipeline = $true, - ValueFromPipelineByPropertyName = $true - )] - [Int[]] $Id, - - # Credentials to use to connect to Jira - [Parameter(Mandatory = $false)] - [System.Management.Automation.PSCredential] $Credential - ) - - begin { - Write-Debug "[Get-JiraIssueLink] Reading server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - - $uri = "$server/rest/api/2/issueLink/{0}" - } - - process { - # Validate input object from Pipeline - if (($_) -and ($_.PSObject.TypeNames[0] -ne "PSJira.IssueLink")) { - $message = "Wrong object type provided for IssueLink." - $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message - Throw $exception - } - - foreach ($ilink in $Id) { - Write-Debug "[Get-JiraIssueLink] Processing project [$ilink]" - $thisUri = $uri -f $ilink - - Write-Debug "[Get-JiraIssueLink] Preparing for blastoff!" - - $result = Invoke-JiraMethod -Method Get -URI $thisUri -Credential $Credential - if ($result) { - Write-Debug "[Get-JiraIssueLink] Converting to object" - $obj = ConvertTo-JiraIssueLink -InputObject $result - - Write-Debug "[Get-JiraIssueLink] Outputting result" - Write-Output $obj - } - else { - Write-Debug "[Get-JiraIssueLink] No results were returned from Jira" - Write-Debug "[Get-JiraIssueLink] No results were returned from Jira for project [$ilink]" - } - } - } - - end { - Write-Debug "[Get-JiraIssueLink] Complete" - } -} - - +function Get-JiraIssueLink { + <# + .Synopsis + Returns a specific issueLink from Jira + .DESCRIPTION + This function returns information regarding a specified issueLink from Jira. + .EXAMPLE + Get-JiraIssueLink 10000 + Returns information about the IssueLink with ID 10000 + .EXAMPLE + Get-JiraIssueLink -IssueLink 10000 + Returns information about the IssueLink with ID 10000 + .EXAMPLE + (Get-JiraIssue TEST-01).issuelinks | Get-JiraIssueLink + Returns the information about all IssueLinks in issue TEST-01 + .INPUTS + [Int[]] issueLink ID + [PSCredential] Credentials to use to connect to Jira + .OUTPUTS + [JiraPS.IssueLink] + #> + [CmdletBinding()] + param( + # The IssueLink ID to search + # + # Accepts input from pipeline when the object is of type JiraPS.IssueLink + [Parameter( + Position = 0, + Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true + )] + [Int[]] $Id, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin { + Write-Debug "[Get-JiraIssueLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + $uri = "$server/rest/api/2/issueLink/{0}" + } + + process { + # Validate input object from Pipeline + if (($_) -and ($_.PSObject.TypeNames[0] -ne "JiraPS.IssueLink")) { + $message = "Wrong object type provided for IssueLink." + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + foreach ($ilink in $Id) { + Write-Debug "[Get-JiraIssueLink] Processing project [$ilink]" + $thisUri = $uri -f $ilink + + Write-Debug "[Get-JiraIssueLink] Preparing for blastoff!" + + $result = Invoke-JiraMethod -Method Get -URI $thisUri -Credential $Credential + if ($result) { + Write-Debug "[Get-JiraIssueLink] Converting to object" + $obj = ConvertTo-JiraIssueLink -InputObject $result + + Write-Debug "[Get-JiraIssueLink] Outputting result" + Write-Output $obj + } + else { + Write-Debug "[Get-JiraIssueLink] No results were returned from Jira" + Write-Debug "[Get-JiraIssueLink] No results were returned from Jira for project [$ilink]" + } + } + } + + end { + Write-Debug "[Get-JiraIssueLink] Complete" + } +} + + diff --git a/PSJira/Public/Get-JiraIssueLinkType.ps1 b/JiraPS/Public/Get-JiraIssueLinkType.ps1 similarity index 98% rename from PSJira/Public/Get-JiraIssueLinkType.ps1 rename to JiraPS/Public/Get-JiraIssueLinkType.ps1 index b7df4674..afea1935 100644 --- a/PSJira/Public/Get-JiraIssueLinkType.ps1 +++ b/JiraPS/Public/Get-JiraIssueLinkType.ps1 @@ -16,7 +16,7 @@ function Get-JiraIssueLinkType .INPUTS This function does not accept pipeline input. .OUTPUTS - This function outputs the PSJira.IssueLinkType object(s) that represent the JIRA issue link type(s). + This function outputs the JiraPS.IssueLinkType object(s) that represent the JIRA issue link type(s). .NOTES This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> diff --git a/JiraPS/Public/Get-JiraIssueType.ps1 b/JiraPS/Public/Get-JiraIssueType.ps1 index b4683372..53638bdb 100644 --- a/JiraPS/Public/Get-JiraIssueType.ps1 +++ b/JiraPS/Public/Get-JiraIssueType.ps1 @@ -4,7 +4,7 @@ .Synopsis Returns information about the available issue type in JIRA. .DESCRIPTION - This function retrieves all the available IssueType on the JIRA server an returns them as PSJira.IssueType. + This function retrieves all the available IssueType on the JIRA server an returns them as JiraPS.IssueType. This function can restrict the output to a subset of the available IssueTypes if told so. .EXAMPLE @@ -19,7 +19,7 @@ .INPUTS This function accepts Strings via the pipeline. .OUTPUTS - This function outputs the PSJira.IssueType object retrieved. + This function outputs the JiraPS.IssueType object retrieved. .NOTES This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> diff --git a/PSJira/Public/Get-JiraIssueWatcher.ps1 b/JiraPS/Public/Get-JiraIssueWatcher.ps1 similarity index 93% rename from PSJira/Public/Get-JiraIssueWatcher.ps1 rename to JiraPS/Public/Get-JiraIssueWatcher.ps1 index 01810f53..09860568 100644 --- a/PSJira/Public/Get-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Get-JiraIssueWatcher.ps1 @@ -12,15 +12,15 @@ Get-JiraIssue TEST-002 | Get-JiraIssueWatcher This example illustrates use of the pipeline to return all watchers on issue TEST-002. .INPUTS - This function can accept PSJira.Issue objects, Strings, or Objects via the pipeline. It uses Get-JiraIssue to identify the issue parameter; see its Inputs section for details on how this function handles inputs. + This function can accept JiraPS.Issue objects, Strings, or Objects via the pipeline. It uses Get-JiraIssue to identify the issue parameter; see its Inputs section for details on how this function handles inputs. .OUTPUTS - This function outputs all PSJira.Watchers issues associated with the provided issue. + This function outputs all JiraPS.Watchers issues associated with the provided issue. .NOTES This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> [CmdletBinding()] param( - # JIRA issue to check for watchers. Can be a PSJira.Issue object, issue key, or internal issue ID. + # JIRA issue to check for watchers. Can be a JiraPS.Issue object, issue key, or internal issue ID. [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, diff --git a/JiraPS/Public/Get-JiraPriority.ps1 b/JiraPS/Public/Get-JiraPriority.ps1 index 0bd2095c..cc4314ea 100644 --- a/JiraPS/Public/Get-JiraPriority.ps1 +++ b/JiraPS/Public/Get-JiraPriority.ps1 @@ -4,7 +4,7 @@ function Get-JiraPriority .Synopsis Returns information about the available priorities in JIRA. .DESCRIPTION - This function retrieves all the available Priorities on the JIRA server an returns them as PSJira.Priority. + This function retrieves all the available Priorities on the JIRA server an returns them as JiraPS.Priority. This function can restrict the output to a subset of the available IssueTypes if told so. .EXAMPLE @@ -14,7 +14,7 @@ function Get-JiraPriority Get-JiraPriority -ID 1 This example returns only the Priority with ID 1. .OUTPUTS - This function outputs the PSJira.Priority object retrieved. + This function outputs the JiraPS.Priority object retrieved. .NOTES This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. #> diff --git a/PSJira/Public/Get-JiraRemoteLink.ps1 b/JiraPS/Public/Get-JiraRemoteLink.ps1 similarity index 94% rename from PSJira/Public/Get-JiraRemoteLink.ps1 rename to JiraPS/Public/Get-JiraRemoteLink.ps1 index df3ad855..28d480ef 100644 --- a/PSJira/Public/Get-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Get-JiraRemoteLink.ps1 @@ -1,85 +1,85 @@ -function Get-JiraRemoteLink -{ - <# - .Synopsis - Returns a remote link from a Jira issue - .DESCRIPTION - This function returns information on remote links from a JIRA issue. - .EXAMPLE - Get-JiraRemoteLink -Issue Project1-1000 -Credential $cred - Returns information about all remote links from the issue "Project1-1000" - .EXAMPLE - Get-JiraRemoteLink -Issue Project1-1000 -LinkId 100000 -Credential $cred - Returns information about a specific remote link from the issue "Project1-1000" - .INPUTS - [Object[]] The issue to look up in JIRA. This can be a String or a PSJira.Issue object. - .OUTPUTS - [PSJira.Link] - #> - [CmdletBinding()] - param( - # The Issue Object or ID to link. - [Parameter(ValueFromPipelineByPropertyName = $true, - ValueFromPipeline = $true, - Mandatory = $true, - Position = 0 - )] - [Alias("Key")] - [String[]]$Issue, - - # Get a single link by it's id. - [Int]$LinkId, - - # Credentials to use to connect to JIRA. - # If not specified, this function will use anonymous access. - [Parameter(Mandatory = $false)] - [PSCredential] $Credential - ) - - Begin - { - Write-Debug "[Get-JiraRemoteLink] Reading server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - - Write-Debug "[Get-JiraRemoteLink] ParameterSetName=$($PSCmdlet.ParameterSetName)" - - Write-Debug "[Get-JiraRemoteLink] Building URI for REST call" - $linkUrl = "$server/rest/api/latest/issue/{0}/remotelink" - } - - Process - { - foreach ($k in $Issue) - { - Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" - $thisUrl = $linkUrl -f $k - - if ($linkId) - { - $thisUrl += "/$l" - } - - Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" - $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential - - if ($result) - { - Write-Debug "[Get-JiraRemoteLink] Converting results to PSJira.Group" - $obj = ConvertTo-JiraLink -InputObject $result - - Write-Debug "[Get-JiraRemoteLink] Outputting results" - Write-Output $obj - } - else - { - Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" - Write-Verbose "No results were returned from JIRA." - } - } - } - - End - { - Write-Debug "[Get-JiraRemoteLink] Complete" - } -} +function Get-JiraRemoteLink +{ + <# + .Synopsis + Returns a remote link from a Jira issue + .DESCRIPTION + This function returns information on remote links from a JIRA issue. + .EXAMPLE + Get-JiraRemoteLink -Issue Project1-1000 -Credential $cred + Returns information about all remote links from the issue "Project1-1000" + .EXAMPLE + Get-JiraRemoteLink -Issue Project1-1000 -LinkId 100000 -Credential $cred + Returns information about a specific remote link from the issue "Project1-1000" + .INPUTS + [Object[]] The issue to look up in JIRA. This can be a String or a JiraPS.Issue object. + .OUTPUTS + [JiraPS.Link] + #> + [CmdletBinding()] + param( + # The Issue Object or ID to link. + [Parameter(ValueFromPipelineByPropertyName = $true, + ValueFromPipeline = $true, + Mandatory = $true, + Position = 0 + )] + [Alias("Key")] + [String[]]$Issue, + + # Get a single link by it's id. + [Int]$LinkId, + + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. + [Parameter(Mandatory = $false)] + [PSCredential] $Credential + ) + + Begin + { + Write-Debug "[Get-JiraRemoteLink] Reading server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + Write-Debug "[Get-JiraRemoteLink] ParameterSetName=$($PSCmdlet.ParameterSetName)" + + Write-Debug "[Get-JiraRemoteLink] Building URI for REST call" + $linkUrl = "$server/rest/api/latest/issue/{0}/remotelink" + } + + Process + { + foreach ($k in $Issue) + { + Write-Debug "[Get-JiraRemoteLink] Processing issue key [$k]" + $thisUrl = $linkUrl -f $k + + if ($linkId) + { + $thisUrl += "/$l" + } + + Write-Debug "[Get-JiraRemoteLink] Preparing for blastoff!" + $result = Invoke-JiraMethod -Method Get -URI $thisUrl -Credential $Credential + + if ($result) + { + Write-Debug "[Get-JiraRemoteLink] Converting results to JiraPS.Group" + $obj = ConvertTo-JiraLink -InputObject $result + + Write-Debug "[Get-JiraRemoteLink] Outputting results" + Write-Output $obj + } + else + { + Write-Debug "[Get-JiraRemoteLink] No results were returned from JIRA" + Write-Verbose "No results were returned from JIRA." + } + } + } + + End + { + Write-Debug "[Get-JiraRemoteLink] Complete" + } +} diff --git a/PSJira/Public/Remove-JiraIssueLink.ps1 b/JiraPS/Public/Remove-JiraIssueLink.ps1 similarity index 86% rename from PSJira/Public/Remove-JiraIssueLink.ps1 rename to JiraPS/Public/Remove-JiraIssueLink.ps1 index fd6aff55..a28ca411 100644 --- a/PSJira/Public/Remove-JiraIssueLink.ps1 +++ b/JiraPS/Public/Remove-JiraIssueLink.ps1 @@ -1,79 +1,79 @@ -function Remove-JiraIssueLink { - <# - .Synopsis - Removes a issue link from a JIRA issue - .DESCRIPTION - This function removes a issue link from a JIRA issue. - .EXAMPLE - Remove-JiraIssueLink 1234,2345 - Removes two issue links with id 1234 and 2345 - .EXAMPLE - Get-JiraIssue -Query "project = Project1 AND label = lingering" | Remove-JiraIssueLink - Removes all issue links for all issues in project Project1 and that have a label "lingering" - .INPUTS - [PSJira.IssueLink[]] The JIRA issue link which to delete - .OUTPUTS - This function returns no output. - #> - [CmdletBinding( - SupportsShouldProcess = $true, - ConfirmImpact = 'Medium' - )] - param( - # IssueLink to delete - [Parameter( - Position = 0, - Mandatory = $true, - ValueFromPipeline = $true - )] - [Object[]] $IssueLink, - - # Credentials to use to connect to Jira - [Parameter(Mandatory = $false)] - [PSCredential] $Credential - ) - - Begin { - Write-Debug "[Remove-JiraIssueLink] Reading Jira server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - - $restUrl = "$server/rest/api/latest/issueLink/{0}" - } - - Process { - - # As we are not able to use proper type casting in the parameters, this is a workaround - # to extract the data from a PSJira.Issue object - if (($_) -and ($_.PSObject.TypeNames[0] -eq "PSJira.Issue")) { - $IssueLink = $_.issueLinks - } - - # Validate IssueLink object - $objectProperties = $IssueLink | Get-Member -MemberType *Property - if (-not($objectProperties.Name -contains "id")) { - $message = "The IssueLink provided does not contain the information needed. $($objectProperties | Out-String)" - $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message - Throw $exception - } - - # Validate input object from Pipeline - if (($_) -and ($_.PSObject.TypeNames[0] -notin @("PSJira.IssueLink", "PSJira.Issue"))) { - $message = "Wrong object type provided for Issue. Only PSJira.IssueLink is accepted" - $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message - Throw $exception - } - - foreach ($link in $IssueLink) { - Write-Debug "[Remove-JiraIssueLink] Processing issue key [$k]" - $thisUrl = $restUrl -f $link.id - if ($PSCmdlet.ShouldProcess($link.id, "Remove IssueLink")) { - Write-Debug "[Remove-JiraIssueLink] Preparing for blastoff!" - Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential - } - } - } - - End { - Write-Debug "[Remove-JiraIssueLink] Complete" - } -} +function Remove-JiraIssueLink { + <# + .Synopsis + Removes a issue link from a JIRA issue + .DESCRIPTION + This function removes a issue link from a JIRA issue. + .EXAMPLE + Remove-JiraIssueLink 1234,2345 + Removes two issue links with id 1234 and 2345 + .EXAMPLE + Get-JiraIssue -Query "project = Project1 AND label = lingering" | Remove-JiraIssueLink + Removes all issue links for all issues in project Project1 and that have a label "lingering" + .INPUTS + [JiraPS.IssueLink[]] The JIRA issue link which to delete + .OUTPUTS + This function returns no output. + #> + [CmdletBinding( + SupportsShouldProcess = $true, + ConfirmImpact = 'Medium' + )] + param( + # IssueLink to delete + [Parameter( + Position = 0, + Mandatory = $true, + ValueFromPipeline = $true + )] + [Object[]] $IssueLink, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [PSCredential] $Credential + ) + + Begin { + Write-Debug "[Remove-JiraIssueLink] Reading Jira server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + + $restUrl = "$server/rest/api/latest/issueLink/{0}" + } + + Process { + + # As we are not able to use proper type casting in the parameters, this is a workaround + # to extract the data from a JiraPS.Issue object + if (($_) -and ($_.PSObject.TypeNames[0] -eq "JiraPS.Issue")) { + $IssueLink = $_.issueLinks + } + + # Validate IssueLink object + $objectProperties = $IssueLink | Get-Member -MemberType *Property + if (-not($objectProperties.Name -contains "id")) { + $message = "The IssueLink provided does not contain the information needed. $($objectProperties | Out-String)" + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + # Validate input object from Pipeline + if (($_) -and ($_.PSObject.TypeNames[0] -notin @("JiraPS.IssueLink", "JiraPS.Issue"))) { + $message = "Wrong object type provided for Issue. Only JiraPS.IssueLink is accepted" + $exception = New-Object -TypeName System.ArgumentException -ArgumentList $message + Throw $exception + } + + foreach ($link in $IssueLink) { + Write-Debug "[Remove-JiraIssueLink] Processing issue key [$k]" + $thisUrl = $restUrl -f $link.id + if ($PSCmdlet.ShouldProcess($link.id, "Remove IssueLink")) { + Write-Debug "[Remove-JiraIssueLink] Preparing for blastoff!" + Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential + } + } + } + + End { + Write-Debug "[Remove-JiraIssueLink] Complete" + } +} diff --git a/PSJira/Public/Remove-JiraIssueWatcher.ps1 b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 similarity index 97% rename from PSJira/Public/Remove-JiraIssueWatcher.ps1 rename to JiraPS/Public/Remove-JiraIssueWatcher.ps1 index a949f45c..ce05c91f 100644 --- a/PSJira/Public/Remove-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 @@ -15,7 +15,7 @@ Get-JiraIssue -Query 'project = "TEST" AND created >= -5d' | % { Remove-JiraIssueWatcher "fred" } This example illustrates removing watcher on all projects which match a given JQL query. It would be best to validate the query first to make sure the query returns the expected issues! .INPUTS - This function can accept PSJira.Issue objects via pipeline. + This function can accept JiraPS.Issue objects via pipeline. .OUTPUTS This function does not provide output. .NOTES diff --git a/PSJira/Public/Remove-JiraRemoteLink.ps1 b/JiraPS/Public/Remove-JiraRemoteLink.ps1 similarity index 95% rename from PSJira/Public/Remove-JiraRemoteLink.ps1 rename to JiraPS/Public/Remove-JiraRemoteLink.ps1 index d6163ccd..e14caeea 100644 --- a/PSJira/Public/Remove-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Remove-JiraRemoteLink.ps1 @@ -1,104 +1,104 @@ -function Remove-JiraRemoteLink -{ - <# - .Synopsis - Removes a remote link from a JIRA issue - .DESCRIPTION - This function removes a remote link from a JIRA issue. - .EXAMPLE - Remove-JiraRemoteLink Project1-1001 10000,20000 - Removes two remote link from issue "Project1-1001" - .EXAMPLE - Get-JiraIssue -Query "project = Project1" | Remove-JiraRemoteLink 10000 - Removes a specific remote link from all issues in project "Project1" - .INPUTS - [PSJira.Issue[]] The JIRA issue from which to delete a link - .OUTPUTS - This function returns no output. - #> - [CmdletBinding(SupportsShouldProcess = $true, - ConfirmImpact = 'High')] - param( - # Issue from which to delete a remote link. - [Parameter(ValueFromPipelineByPropertyName = $true, - ValueFromPipeline = $true, - Mandatory = $true, - Position = 0 - )] - [Alias("Key")] - [Object[]] $Issue, - - # Id of the remote link to delete. - [Parameter(Mandatory = $true)] - [Int[]] $LinkId, - - # Credentials to use to connect to JIRA. - # If not specified, this function will use anonymous access. - [Parameter(Mandatory = $false)] - [PSCredential] $Credential, - - # Suppress user confirmation. - [Switch] $Force - ) - - Begin - { - try - { - Write-Debug "[Remove-JiraRemoteLink] Reading Jira server from config file" - $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop - } catch - { - $err = $_ - Write-Debug "[Remove-JiraRemoteLink] Encountered an error reading configuration data." - throw $err - } - - $restUrl = "$server/rest/api/latest/issue/{0}/remotelink/{1}" - - if ($Force) - { - Write-Debug "[Remove-JiraRemoteLink] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" - $oldConfirmPreference = $ConfirmPreference - $ConfirmPreference = 'None' - } - } - - Process - { - - foreach ($k in $Issue) - { - Write-Debug "[Remove-JiraRemoteLink] Processing issue key [$k]" - $issueObj = Get-JiraIssue $k -Credential $Credential - - foreach ($l in $LinkId) - { - $thisUrl = $restUrl -f $k, $l - Write-Debug "[Remove-JiraRemoteLink] RemoteLink URL: [$thisUrl]" - - Write-Debug "[Remove-JiraRemoteLink] Checking for -WhatIf and Confirm" - if ($PSCmdlet.ShouldProcess($issueObj.Key, "Remove RemoteLink from [$issueObj] from JIRA")) - { - Write-Debug "[Remove-JiraRemoteLink] Preparing for blastoff!" - Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential - } - else - { - Write-Debug "[Remove-JiraRemoteLink] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" - } - } - } - } - - End - { - if ($Force) - { - Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" - $ConfirmPreference = $oldConfirmPreference - } - - Write-Debug "[Remove-JiraRemoteLink] Complete" - } -} +function Remove-JiraRemoteLink +{ + <# + .Synopsis + Removes a remote link from a JIRA issue + .DESCRIPTION + This function removes a remote link from a JIRA issue. + .EXAMPLE + Remove-JiraRemoteLink Project1-1001 10000,20000 + Removes two remote link from issue "Project1-1001" + .EXAMPLE + Get-JiraIssue -Query "project = Project1" | Remove-JiraRemoteLink 10000 + Removes a specific remote link from all issues in project "Project1" + .INPUTS + [JiraPS.Issue[]] The JIRA issue from which to delete a link + .OUTPUTS + This function returns no output. + #> + [CmdletBinding(SupportsShouldProcess = $true, + ConfirmImpact = 'High')] + param( + # Issue from which to delete a remote link. + [Parameter(ValueFromPipelineByPropertyName = $true, + ValueFromPipeline = $true, + Mandatory = $true, + Position = 0 + )] + [Alias("Key")] + [Object[]] $Issue, + + # Id of the remote link to delete. + [Parameter(Mandatory = $true)] + [Int[]] $LinkId, + + # Credentials to use to connect to JIRA. + # If not specified, this function will use anonymous access. + [Parameter(Mandatory = $false)] + [PSCredential] $Credential, + + # Suppress user confirmation. + [Switch] $Force + ) + + Begin + { + try + { + Write-Debug "[Remove-JiraRemoteLink] Reading Jira server from config file" + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + } catch + { + $err = $_ + Write-Debug "[Remove-JiraRemoteLink] Encountered an error reading configuration data." + throw $err + } + + $restUrl = "$server/rest/api/latest/issue/{0}/remotelink/{1}" + + if ($Force) + { + Write-Debug "[Remove-JiraRemoteLink] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" + $oldConfirmPreference = $ConfirmPreference + $ConfirmPreference = 'None' + } + } + + Process + { + + foreach ($k in $Issue) + { + Write-Debug "[Remove-JiraRemoteLink] Processing issue key [$k]" + $issueObj = Get-JiraIssue $k -Credential $Credential + + foreach ($l in $LinkId) + { + $thisUrl = $restUrl -f $k, $l + Write-Debug "[Remove-JiraRemoteLink] RemoteLink URL: [$thisUrl]" + + Write-Debug "[Remove-JiraRemoteLink] Checking for -WhatIf and Confirm" + if ($PSCmdlet.ShouldProcess($issueObj.Key, "Remove RemoteLink from [$issueObj] from JIRA")) + { + Write-Debug "[Remove-JiraRemoteLink] Preparing for blastoff!" + Invoke-JiraMethod -Method Delete -URI $thisUrl -Credential $Credential + } + else + { + Write-Debug "[Remove-JiraRemoteLink] Runnning in WhatIf mode or user denied the Confirm prompt; no operation will be performed" + } + } + } + } + + End + { + if ($Force) + { + Write-Debug "[Remove-JiraGroupMember] Restoring ConfirmPreference to [$oldConfirmPreference]" + $ConfirmPreference = $oldConfirmPreference + } + + Write-Debug "[Remove-JiraRemoteLink] Complete" + } +} diff --git a/JiraPS/Public/Remove-JiraSession.ps1 b/JiraPS/Public/Remove-JiraSession.ps1 index 30715503..40930206 100644 --- a/JiraPS/Public/Remove-JiraSession.ps1 +++ b/JiraPS/Public/Remove-JiraSession.ps1 @@ -56,12 +56,12 @@ function Remove-JiraSession { process { if ($Session) { Write-Debug "[Remove-JiraSession] Validating Session parameter" - if ((Get-Member -InputObject $Session).TypeName -eq 'PSJira.Session') { + if ((Get-Member -InputObject $Session).TypeName -eq 'JiraPS.Session') { Write-Debug "[Remove-JiraSession] Successfully parsed Session parameter as a JiraPS.Session object" } else { - Write-Debug "[Remove-JiraSession] Session parameter is not a PSJira.Session object. Throwing exception" - throw "Unable to parse parameter [$Session] as a PSJira.Session object" + Write-Debug "[Remove-JiraSession] Session parameter is not a JiraPS.Session object. Throwing exception" + throw "Unable to parse parameter [$Session] as a JiraPS.Session object" } } else { diff --git a/Tests/Add-JiraIssueLink.Tests.ps1 b/Tests/Add-JiraIssueLink.Tests.ps1 index ad1f0352..c8157aa8 100644 --- a/Tests/Add-JiraIssueLink.Tests.ps1 +++ b/Tests/Add-JiraIssueLink.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] $SuppressImportModule = $true @@ -17,7 +17,7 @@ InModuleScope PSJira { Describe 'Add-JiraIssueLink' { - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } @@ -28,7 +28,7 @@ InModuleScope PSJira { } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } @@ -56,7 +56,7 @@ InModuleScope PSJira { It 'Adds a new IssueLink' { { Add-JiraIssueLink -Issue $issueKey -IssueLink $issueLink } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It 'Validates the IssueType provided' { diff --git a/Tests/Add-JiraIssueWatcher.Tests.ps1 b/Tests/Add-JiraIssueWatcher.Tests.ps1 index 5d616733..db3e9ed4 100644 --- a/Tests/Add-JiraIssueWatcher.Tests.ps1 +++ b/Tests/Add-JiraIssueWatcher.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] $SuppressImportModule = $true @@ -12,11 +12,11 @@ InModuleScope PSJira { Describe "Add-JiraIssueWatcher" { - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } - Mock Get-JiraIssue -ModuleName PSJira { + Mock Get-JiraIssue -ModuleName JiraPS { [PSCustomObject] @{ ID = $issueID; Key = $issueKey; @@ -24,12 +24,12 @@ InModuleScope PSJira { } } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' throw "Unidentified call to Invoke-JiraMethod" } @@ -53,10 +53,10 @@ InModuleScope PSJira { $WatcherResult | Should BeNullOrEmpty # Get-JiraIssue should be used to identify the issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 1 -Scope It # Invoke-JiraMethod should be used to add the Watcher - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Accepts pipeline input from Get-JiraIssue" { @@ -64,8 +64,8 @@ InModuleScope PSJira { $WatcherResult | Should BeNullOrEmpty # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } } } diff --git a/Tests/Add-JiraIssueWorklog.Tests.ps1 b/Tests/Add-JiraIssueWorklog.Tests.ps1 index 483324d9..7cd48796 100644 --- a/Tests/Add-JiraIssueWorklog.Tests.ps1 +++ b/Tests/Add-JiraIssueWorklog.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { $ShowMockData = $false @@ -53,21 +53,21 @@ InModuleScope PSJira { Describe "Add-JiraIssueWorklog" { - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } - Mock Get-JiraIssue -ModuleName PSJira { + Mock Get-JiraIssue -ModuleName JiraPS { $result = [PSCustomObject] @{ ID = $issueID; Key = $issueKey; RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; } - $result.PSObject.TypeNames.Insert(0, 'PSJira.Issue') + $result.PSObject.TypeNames.Insert(0, 'JiraPS.Issue') Write-Output $result } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/worklog"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/worklog"} { if ($ShowMockData) { Write-Host " Mocked Invoke-JiraMethod with POST method" -ForegroundColor Cyan @@ -81,7 +81,7 @@ InModuleScope PSJira { } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed Write-Host " [Method] $Method" -ForegroundColor DarkRed Write-Host " [URI] $URI" -ForegroundColor DarkRed @@ -97,10 +97,10 @@ InModuleScope PSJira { $commentResult | Should Not BeNullOrEmpty # Get-JiraIssue should be used to identify the issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 1 -Scope It # Invoke-JiraMethod should be used to add the comment - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Accepts pipeline input from Get-JiraIssue" { @@ -108,8 +108,8 @@ InModuleScope PSJira { $commentResult | Should Not BeNullOrEmpty # Get-JiraIssue should be called once here to fetch the initial test issue - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } } } diff --git a/Tests/ConvertTo-JiraIssueLink.Tests.ps1 b/Tests/ConvertTo-JiraIssueLink.Tests.ps1 index 2a27bbfd..8c7a6d2f 100644 --- a/Tests/ConvertTo-JiraIssueLink.Tests.ps1 +++ b/Tests/ConvertTo-JiraIssueLink.Tests.ps1 @@ -1,5 +1,5 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { Describe "ConvertTo-JiraIssueLink" { . $PSScriptRoot\Shared.ps1 @@ -35,7 +35,7 @@ InModuleScope PSJira { $r | Should Not BeNullOrEmpty } - checkPsType $r 'PSJira.IssueLink' + checkPsType $r 'JiraPS.IssueLink' defProp $r 'Id' $issueLinkId defProp $r 'Type' "Composition" diff --git a/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 b/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 index d135002a..9653ad8c 100644 --- a/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 +++ b/Tests/ConvertTo-JiraIssueLinkType.Tests.ps1 @@ -1,5 +1,5 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { Describe "ConvertTo-JiraIssueLinkType" { . $PSScriptRoot\Shared.ps1 @@ -46,8 +46,8 @@ InModuleScope PSJira { It "Creates a PSObject out of JSON input" { $r | Should Not BeNullOrEmpty } - - checkPsType $r 'PSJira.IssueLinkType' + + checkPsType $r 'JiraPS.IssueLinkType' defProp $r 'Id' '10000' defProp $r 'Name' 'Blocks' diff --git a/Tests/ConvertTo-JiraLink.Tests.ps1 b/Tests/ConvertTo-JiraLink.Tests.ps1 index 7305e38b..8aabac93 100644 --- a/Tests/ConvertTo-JiraLink.Tests.ps1 +++ b/Tests/ConvertTo-JiraLink.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { Describe "ConvertTo-JiraLink" { . $PSScriptRoot\Shared.ps1 @@ -44,7 +44,7 @@ InModuleScope PSJira { $r | Should Not BeNullOrEmpty } - checkPsType $r 'PSJira.Link' + checkPsType $r 'JiraPS.Link' defProp $r 'id' $LinkId defProp $r 'RestUrl' "$jiraServer/rest/api/issue/MKY-1/remotelink/10000" diff --git a/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 b/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 index 57707951..9c037b20 100644 --- a/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 +++ b/Tests/ConvertTo-JiraWorklogitem.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { Describe "ConvertTo-JiraWorklogitem" { function defProp($obj, $propName, $propValue) { @@ -65,9 +65,9 @@ InModuleScope PSJira { $r | Should Not BeNullOrEmpty } - It "Sets the type name to PSJira.WorklogItem" { + It "Sets the type name to JiraPS.WorklogItem" { $r = ConvertTo-JiraWorklogitem -InputObject $sampleObject - $r.PSObject.TypeNames[0] | Should Be 'PSJira.WorklogItem' + $r.PSObject.TypeNames[0] | Should Be 'JiraPS.WorklogItem' } $r = ConvertTo-JiraWorklogitem -InputObject $sampleObject diff --git a/Tests/Get-JiraIssueLink.Tests.ps1 b/Tests/Get-JiraIssueLink.Tests.ps1 index 6f4f2055..86802fb5 100644 --- a/Tests/Get-JiraIssueLink.Tests.ps1 +++ b/Tests/Get-JiraIssueLink.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] $SuppressImportModule = $true @@ -22,28 +22,28 @@ InModuleScope PSJira { "@ Describe "Get-JiraIssueLink" { - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/2/issueLink/1234"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/2/issueLink/1234"} { ConvertFrom-Json2 $resultsJson } - Mock Get-JiraIssue -ModuleName PSJira -ParameterFilter {$Key -eq "TEST-01"} { + Mock Get-JiraIssue -ModuleName JiraPS -ParameterFilter {$Key -eq "TEST-01"} { # We don't care about the content of any field except for the id $obj = [PSCustomObject]@{ "id" = $issueLinkId "type" = "foo" "inwardIssue" = "bar" } - $obj.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + $obj.PSObject.TypeNames.Insert(0, 'JiraPS.IssueLink') return [PSCustomObject]@{ issueLinks = @( $obj diff --git a/Tests/Get-JiraIssueLinkType.Tests.ps1 b/Tests/Get-JiraIssueLinkType.Tests.ps1 index a3ec33b3..346d0d04 100644 --- a/Tests/Get-JiraIssueLinkType.Tests.ps1 +++ b/Tests/Get-JiraIssueLinkType.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] $SuppressImportModule = $true @@ -9,8 +9,8 @@ InModuleScope PSJira { $jiraServer = 'http://jiraserver.example.com' Describe 'Get-JiraIssueLinkType' { - - Mock Get-JiraConfigServer -ModuleName PSJira { + + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } @@ -25,7 +25,7 @@ InModuleScope PSJira { $filterOne = {$Method -eq 'Get' -and $Uri -ceq "$jiraServer/rest/api/latest/issueLinkType/10000"} # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } @@ -56,7 +56,7 @@ InModuleScope PSJira { # We also don't care what comes out of here - this function has its own tests [PSCustomObject] @{ - PSTypeName = 'PSJira.IssueLinkType' + PSTypeName = 'JiraPS.IssueLinkType' foo = 'bar' } } @@ -82,7 +82,7 @@ InModuleScope PSJira { # We also don't care what comes out of here - this function has its own tests [PSCustomObject] @{ - PSTypeName = 'PSJira.IssueLinkType' + PSTypeName = 'JiraPS.IssueLinkType' Name = 'myLink' ID = 5 } diff --git a/Tests/Get-JiraIssueWatcher.Tests.ps1 b/Tests/Get-JiraIssueWatcher.Tests.ps1 index a58fd981..15272e5d 100644 --- a/Tests/Get-JiraIssueWatcher.Tests.ps1 +++ b/Tests/Get-JiraIssueWatcher.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] $SuppressImportModule = $true @@ -31,11 +31,11 @@ InModuleScope PSJira { ] } "@ - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } - Mock Get-JiraIssue -ModuleName PSJira { + Mock Get-JiraIssue -ModuleName JiraPS { [PSCustomObject] @{ ID = $issueID; Key = $issueKey; @@ -44,13 +44,13 @@ InModuleScope PSJira { } # Obtaining watchers from an issue...this is IT-3676 in the test environment - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers"} { ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' ConvertFrom-Json2 -InputObject $restResult } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri','Method' throw "Unidentified call to Invoke-JiraMethod" } @@ -77,11 +77,11 @@ InModuleScope PSJira { $watchers.RestUrl | Should Be "$jiraServer/jira/rest/api/2/user?username=fred" # Get-JiraIssue should be called to identify the -Issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 1 -Scope It # Normally, this would be called once in Get-JiraIssue and a second time in Get-JiraIssueWatcher, but # since we've mocked Get-JiraIssue out, it will only be called once. - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Obtains all Jira watchers from a Jira issue if the Jira object is provided" { @@ -89,14 +89,14 @@ InModuleScope PSJira { $watchers = Get-JiraIssueWatcher -Issue $issue $watchers | Should Not BeNullOrEmpty $watchers.name | Should Be "fred" - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Handles pipeline input from Get-JiraIssue" { $watchers = Get-JiraIssue -Key $issueKey | Get-JiraIssueWatcher $watchers | Should Not BeNullOrEmpty $watchers.name | Should Be "fred" - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } } } diff --git a/Tests/Get-JiraRemoteLink.Tests.ps1 b/Tests/Get-JiraRemoteLink.Tests.ps1 index 4ee101bb..b1bb0afe 100644 --- a/Tests/Get-JiraRemoteLink.Tests.ps1 +++ b/Tests/Get-JiraRemoteLink.Tests.ps1 @@ -1,7 +1,7 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { - +InModuleScope JiraPS { + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] $SuppressImportModule = $true . $PSScriptRoot\Shared.ps1 @@ -34,7 +34,7 @@ InModuleScope PSJira { Describe "Get-JiraRemoteLink" { - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } @@ -46,7 +46,7 @@ InModuleScope PSJira { } # Searching for a group. - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Get'} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get'} { if ($ShowMockData) { Write-Host " Mocked Invoke-JiraMethod with GET method" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan @@ -56,7 +56,7 @@ InModuleScope PSJira { } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed Write-Host " [Method] $Method" -ForegroundColor DarkRed Write-Host " [URI] $URI" -ForegroundColor DarkRed diff --git a/Tests/Invoke-JiraIssueTransition.Tests.ps1 b/Tests/Invoke-JiraIssueTransition.Tests.ps1 index b564e725..8cae3c46 100644 --- a/Tests/Invoke-JiraIssueTransition.Tests.ps1 +++ b/Tests/Invoke-JiraIssueTransition.Tests.ps1 @@ -93,11 +93,11 @@ InModuleScope JiraPS { } } { Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Fields @{'customfield_12345'='foo'; 'customfield_67890'='bar'} } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*customfield_12345*set*foo*' } - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*customfield_67890*set*bar*' } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*customfield_12345*set*foo*' } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*customfield_67890*set*bar*' } } - It "Updates assignee name if provided to the -Assignee parameter"{ + It "Updates assignee name if provided to the -Assignee parameter"{ Mock Get-JiraUser { [PSCustomObject] @{ 'Name' = 'powershell-user'; @@ -105,17 +105,17 @@ InModuleScope JiraPS { } } { $result = Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Assignee 'powershell-user'} | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*name*powershell-user*' } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*name*powershell-user*' } } It "Unassigns an issue if 'Unassigned' is passed to the -Assignee parameter"{ { $result = Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Assignee 'Unassigned'} | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*name*""*' } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*name*""*' } } It "Adds a comment if provide to the -Comment parameter"{ { $result = Invoke-JiraIssueTransition -Issue $issueKey -Transition 11 -Comment 'test comment'} | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*body*test comment*' } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "*/rest/api/latest/issue/$issueID/transitions" -and $Body -like '*body*test comment*' } } } } diff --git a/Tests/PSJira.Help.Tests.ps1 b/Tests/PSJira.Help.Tests.ps1 index 202faf06..c65a29b7 100644 --- a/Tests/PSJira.Help.Tests.ps1 +++ b/Tests/PSJira.Help.Tests.ps1 @@ -105,7 +105,7 @@ function Get-ParametersDefaultFirst $here = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = Split-Path -Parent $here -$moduleName = "PSJira" +$moduleName = "JIraPS" $moduleRoot = "$projectRoot\$moduleName" # Removes all versions of the module from the session before importing diff --git a/Tests/Remove-JiraIssueLink.Tests.ps1 b/Tests/Remove-JiraIssueLink.Tests.ps1 index dab842ff..3fffd3e4 100644 --- a/Tests/Remove-JiraIssueLink.Tests.ps1 +++ b/Tests/Remove-JiraIssueLink.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope = '*', Target = 'SuppressImportModule')] $SuppressImportModule = $true @@ -23,44 +23,44 @@ InModuleScope PSJira { Describe "Remove-JiraIssueLink" { $showMockData = $true - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'Delete' -and $URI -eq "$jiraServer/rest/api/latest/issueLink/1234"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Delete' -and $URI -eq "$jiraServer/rest/api/latest/issueLink/1234"} { return $null } - Mock Get-JiraIssue -ModuleName PSJira -ParameterFilter {$Key -eq "TEST-01"} { + Mock Get-JiraIssue -ModuleName JiraPS -ParameterFilter {$Key -eq "TEST-01"} { # We don't care about the content of any field except for the id of the issuelinks $obj = [PSCustomObject]@{ "id" = $issueLinkId "type" = "foo" "inwardIssue" = "bar" } - $obj.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + $obj.PSObject.TypeNames.Insert(0, 'JiraPS.IssueLink') $issue = [PSCustomObject]@{ issueLinks = @( $obj ) } - $issue.PSObject.TypeNames.Insert(0, 'PSJira.Issue') + $issue.PSObject.TypeNames.Insert(0, 'JiraPS.Issue') return $issue } - Mock Get-JiraIssueLink -ModuleName PSJira { + Mock Get-JiraIssueLink -ModuleName JiraPS { $obj = [PSCustomObject]@{ "id" = $issueLinkId "type" = "foo" "inwardIssue" = "bar" } - $obj.PSObject.TypeNames.Insert(0, 'PSJira.IssueLink') + $obj.PSObject.TypeNames.Insert(0, 'JiraPS.IssueLink') return $obj } @@ -84,12 +84,12 @@ InModuleScope PSJira { Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } - It "Accepts a PSJira.Issue object over the pipeline" { + It "Accepts a JiraPS.Issue object over the pipeline" { { Get-JiraIssue -Key TEST-01 | Remove-JiraIssueLink } | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } - It "Accepts a PSJira.IssueType over the pipeline" { + It "Accepts a JiraPS.IssueType over the pipeline" { { Get-JiraIssueLink -Id 1234 | Remove-JiraIssueLink } | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } diff --git a/Tests/Remove-JiraIssueWatcher.Tests.ps1 b/Tests/Remove-JiraIssueWatcher.Tests.ps1 index bad446fc..f2431ec3 100644 --- a/Tests/Remove-JiraIssueWatcher.Tests.ps1 +++ b/Tests/Remove-JiraIssueWatcher.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '', Scope='*', Target='SuppressImportModule')] $SuppressImportModule = $true @@ -12,11 +12,11 @@ InModuleScope PSJira { Describe "Remove-JiraIssueWatcher" { - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } - Mock Get-JiraIssue -ModuleName PSJira { + Mock Get-JiraIssue -ModuleName JiraPS { [PSCustomObject] @{ ID = $issueID; Key = $issueKey; @@ -24,12 +24,12 @@ InModuleScope PSJira { } } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'DELETE' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers?username=fred"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'DELETE' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/watchers?username=fred"} { ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' -Params 'Uri', 'Method' throw "Unidentified call to Invoke-JiraMethod" } @@ -53,10 +53,10 @@ InModuleScope PSJira { $WatcherResult | Should BeNullOrEmpty # Get-JiraIssue should be used to identiyf the issue parameter - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 1 -Scope It # Invoke-JiraMethod should be used to add the Watcher - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Accepts pipeline input from Get-JiraIssue" { @@ -64,8 +64,8 @@ InModuleScope PSJira { $WatcherResult | Should BeNullOrEmpty # Get-JiraIssue should be called once here, and once inside Add-JiraIssueWatcher (to identify the InputObject parameter) - Assert-MockCalled -CommandName Get-JiraIssue -ModuleName PSJira -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } } } diff --git a/Tests/Remove-JiraRemoteLink.Tests.ps1 b/Tests/Remove-JiraRemoteLink.Tests.ps1 index fb148077..d9b83c73 100644 --- a/Tests/Remove-JiraRemoteLink.Tests.ps1 +++ b/Tests/Remove-JiraRemoteLink.Tests.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot\Shared.ps1 -InModuleScope PSJira { +InModuleScope JiraPS { # This is intended to be a parameter to the test, but Pester currently does not allow parameters to be passed to InModuleScope blocks. # For the time being, we'll need to hard-code this and adjust it as desired. @@ -35,14 +35,14 @@ InModuleScope PSJira { Describe "Remove-JiraRemoteLink" { - Mock Write-Debug -ModuleName PSJira { + Mock Write-Debug -ModuleName JiraPS { if ($ShowDebugData) { Write-Host -Object "[DEBUG] $Message" -ForegroundColor Yellow } } - Mock Get-JiraConfigServer -ModuleName PSJira { + Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } @@ -57,7 +57,7 @@ InModuleScope PSJira { ConvertFrom-Json2 $testLink } - Mock Invoke-JiraMethod -ModuleName PSJira -ParameterFilter {$Method -eq 'DELETE'} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'DELETE'} { if ($ShowMockData) { Write-Host " Mocked Invoke-JiraMethod with DELETE method" -ForegroundColor Cyan @@ -68,7 +68,7 @@ InModuleScope PSJira { } # Generic catch-all. This will throw an exception if we forgot to mock something. - Mock Invoke-JiraMethod -ModuleName PSJira { + Mock Invoke-JiraMethod -ModuleName JiraPS { Write-Host " Mocked Invoke-JiraMethod with no parameter filter." -ForegroundColor DarkRed Write-Host " [Method] $Method" -ForegroundColor DarkRed Write-Host " [URI] $URI" -ForegroundColor DarkRed @@ -84,7 +84,7 @@ InModuleScope PSJira { Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } - It "Accepts a PSJira.Issue object to the -Issue parameter" { + It "Accepts a JiraPS.Issue object to the -Issue parameter" { $Issue = Get-JiraIssue $testIssueKey { Remove-JiraRemoteLink -Issue $Issue -LinkId 10000 -Force } | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It diff --git a/build/build.settings.ps1 b/build/build.settings.ps1 index 23ce6bab..79b2f205 100644 --- a/build/build.settings.ps1 +++ b/build/build.settings.ps1 @@ -15,7 +15,7 @@ Properties { # The root directories for the module's docs, src and test. [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $DocsRootDir = "$ProjectRoot\docs" - $SrcRootDir = "$ProjectRoot\PSJira" + $SrcRootDir = "$ProjectRoot\JiraPS" [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] $TestRootDir = "$ProjectRoot\Tests" @@ -187,7 +187,7 @@ Task BeforeBuild { # Executes after the Build task. Task AfterBuild -requiredVariables ProjectRoot,OutDir { - $outputManifestFile = Join-Path -Path $OutDir -ChildPath 'PSJira\PSJira.psd1' + $outputManifestFile = Join-Path -Path $OutDir -ChildPath 'JiraPS\JiraPS.psd1' Write-Host "Patching module manifest file $outputManifestFile" -ForegroundColor Green if ($env:BHBuildSystem -eq 'AppVeyor') { # If we're in AppVeyor, add the build number to the manifest From 706158d7d2607cf1c3275c97f46d437fa2f05ad9 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 25 Jun 2017 17:29:50 +0200 Subject: [PATCH 101/102] Update ChangeLog --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ docs/changelog.rst | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 961f46d6..362a491c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,31 @@ +## 2.1.0 (Jul 25, 2017) + +FEATURES: + - `Get-JiraIssueEditMetadata`: Returns metadata required to create an issue in JIRA (#65, [@lipkau][]) + - `Get-JiraRemoteLink`: Returns a remote link from a JIRA issue (#80, [@lipkau][]) + - `Remove-JiraRemoteLink`: Removes a remote link from a JIRA issue (#80, [@lipkau][]) + - `Get-JiraComponent`: Returns a Component from JIRA (#68, [@axxelG][]) + - `Add-JiraIssueWorklog`: Add worklog items to an issue (#83, [@jkknorr][]) + - Added support for getting and managing Issue Watchers (`Add-JiraIssueWatcher`, `Get-JiraIssueWatcher`, `Remove-JiraIssueWatcher`) (#73, [@ebekker][]) + - Added IssueLink functionality (`Add-JiraIssueLink`, `Get-JiraIssueLink`, `Get-JiraIssueLinkType`, `Remove-JiraIssueLink`) (#131, [@lipkau][]) + +IMPROVEMENTS: + - `New-JiraIssue`: _Description_ and _Priority_ are no longer mandatory (#53, [@brianbunke][]) + - Added property `Components` to `PSjira.Project` (#68, [@axxelG][]) + - `Invoke-JiraIssueTransition`: add support for parameters _Fields_, _Comment_ and _Assignee_ (#38, [@padgers][]) + - `New-JiraIssue`: support parameter _FixVersion_ (#103, [@Dejulia489][]) + - `Set-JiraIssue`: support parameter _FixVersion_ (#103, [@Dejulia489][]) + - Respect the global `$PSDefaultParameterValues` inside the module (#110, [@lipkau][]) + - `New-JiraSession`: Display warning when login needs CAPTCHA (#111, [@lipkau][]) + - Switched to _Basic Authentication_ when generating the session (#116, [@lipkau][]) + - Added more tests for the CI (#142, [@lipkau][]) + +BUG FIXES: + - `Invoke-JiraMethod`: Error when Invoke-WebRequest returns '204 No content' (#42, [@colhal][]) + - `Invoke-JiraIssueTransition`: Error when Invoke-WebRequest returns '204 No content' (#43, [@colhal][]) + - `Set-JiraIssueLabel`: Forced label property to be an array (#88, [@kittholland][]) + - `Invoke-JiraMethod`: Send ContentType as Parameter instead of in the Header (#121, [@lukhase][]) + ## 2.0.0 (Jun 24, 2017) ### Changes to the code module @@ -108,3 +136,17 @@ FEATURES: IMPROVEMENTS: BUG FIXES: + +[@alexsuslin]: https://github.com/alexsuslin +[@axxelG]: https://github.com/axxelG +[@brianbunke]: https://github.com/brianbunke +[@colhal]: https://github.com/colhal +[@Dejulia489]: https://github.com/Dejulia489 +[@ebekker]: https://github.com/ebekker +[@jkknorr]: https://github.com/jkknorr +[@kittholland]: https://github.com/kittholland +[@LiamLeane]: https://github.com/LiamLeane +[@lipkau]: https://github.com/lipkau +[@lukhase]: https://github.com/lukhase +[@padgers]: https://github.com/padgers +[@ThePSAdmin]: https://github.com/ThePSAdmin diff --git a/docs/changelog.rst b/docs/changelog.rst index cb921416..b5f7ed8e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,39 @@ Changelog ========= +Release date: Jun 25, 2017 + +Features +-------- + +* ``Get-JiraIssueEditMetadata``: Returns metadata required to create an issue in JIRA (#65, `@lipkau`_) +* ``Get-JiraRemoteLink``: Returns a remote link from a JIRA issue (#80, `@lipkau`_) +* ``Remove-JiraRemoteLink``: Removes a remote link from a JIRA issue (#80, `@lipkau`_) +* ``Get-JiraComponent``: Returns a Component from JIRA (#68, `@axxelG`_) +* ``Add-JiraIssueWorklog``: Add worklog items to an issue (#83, `@jkknorr`_) +* Added support for getting and managing Issue Watchers (``Add-JiraIssueWatcher``, ``Get-JiraIssueWatcher``, ``Remove-JiraIssueWatcher``) (#73, `@ebekker`_) +* Added IssueLink functionality (``Add-JiraIssueLink``, ``Get-JiraIssueLink``, ``Get-JiraIssueLinkType``, ``Remove-JiraIssueLink``) (#131, `@lipkau`_) + +Improvements +------------ + +* ``New-JiraIssue``: *Description* and *Priority* are no longer mandatory (#53, `@brianbunke`_) +* Added property ``Components`` to ``PSjira.Project`` (#68, `@axxelG`_) +* ``Invoke-JiraIssueTransition``: add support for parameters *Fields*, *Comment* and *Assignee* (#38, `@padgers`_) +* Added support for *FixVersion* parameter in ``New-JiraIssue`` and ``Set-JiraIssue`` (#103, `@Dejulia489`_) +* Respect the global ``$PSDefaultParameterValues`` inside the module (#110, `@lipkau`_) +* ``New-JiraSession``: Display warning when login needs CAPTCHA (#111, `@lipkau`_) +* Switched to *Basic Authentication* when generating the session (#116, `@lipkau`_) +* Added more tests for the CI (#142, `@lipkau`_) + +Bug Fixes +--------- + +* ``Invoke-JiraMethod``: Error when Invoke-WebRequest returns '204 No content' (#42, `@colhal`_) +* ``Invoke-JiraIssueTransition``: Error when Invoke-WebRequest returns '204 No content' (#43, `@colhal`_) +* ``Set-JiraIssueLabel``: Forced label property to be an array (#88, `@kittholland`_) +* ``Invoke-JiraMethod``: Send ContentType as Parameter instead of in the Header (#121, `@lukhase`_) + 2.0.0 ===== @@ -174,3 +207,16 @@ The format of this changelog is inspired by `Pester's changelog`_, which is in t .. _`Pester's changelog`: https://github.com/pester/Pester/blob/master/CHANGELOG.md .. _`Vagrant`: https://github.com/mitchellh/vagrant/blob/master/CHANGELOG.md +.. _`@alexsuslin`: https://github.com/alexsuslin +.. _`@axxelG`: https://github.com/axxelG +.. _`@brianbunke`: https://github.com/brianbunke +.. _`@colhal`: https://github.com/colhal +.. _`@Dejulia489`: https://github.com/Dejulia489 +.. _`@ebekker`: https://github.com/ebekker +.. _`@jkknorr`: https://github.com/jkknorr +.. _`@kittholland`: https://github.com/kittholland +.. _`@LiamLeane`: https://github.com/LiamLeane +.. _`@lipkau`: https://github.com/lipkau +.. _`@lukhase`: https://github.com/lukhase +.. _`@padgers`: https://github.com/padgers +.. _`@ThePSAdmin`: https://github.com/ThePSAdmin From a6f6d7eea912b2f3a1d157f2667643c90296ed21 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 25 Jun 2017 17:29:59 +0200 Subject: [PATCH 102/102] Version Bump --- JiraPS/JiraPS.psd1 | 2 +- appveyor.yml | 2 +- docs/conf.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/JiraPS/JiraPS.psd1 b/JiraPS/JiraPS.psd1 index 4c68b92a..49707676 100644 --- a/JiraPS/JiraPS.psd1 +++ b/JiraPS/JiraPS.psd1 @@ -12,7 +12,7 @@ RootModule = 'JiraPS.psm1' # Version number of this module. -ModuleVersion = '2.0.0' +ModuleVersion = '2.1.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/appveyor.yml b/appveyor.yml index 5cc0d9a9..f854b76a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,7 +20,7 @@ environment: PSGalleryAPIKey: secure: 5WCRuuF+sk5Mjnt5cL6uJw4cMU2QzDNE8uBXOw2hXSujE93zxRcROS3ZM1w85ui3 -version: 2.0.0.{build} +version: 2.1.0.{build} # Only build commits to these branches branches: diff --git a/docs/conf.py b/docs/conf.py index ed7c44eb..285c2a28 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,9 +56,9 @@ # built documents. # # The short X.Y version. -version = '1.2.5' +version = '2.1.0' # The full version, including alpha/beta/rc tags. -release = '1.2.5' +release = '2.1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages.