From 0aa2cd58be7218a9e13689688ffc602e8d337c31 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Thu, 5 Jul 2018 14:01:13 -0500 Subject: [PATCH 01/29] Adding parameter for fields --- JiraPS/Public/Get-JiraIssue.ps1 | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 517b83fb..775b8848 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -7,6 +7,12 @@ function Get-JiraIssue { [Alias('Issue')] [String[]] $Key, + #added Fields Parameter + [Parameter(Mandatory=$false)] + [ValidateNotNullOrEmpty()] + [String[]] + $Fields, + [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] @@ -90,13 +96,16 @@ function Get-JiraIssue { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" $server = Get-JiraConfigServer -ErrorAction Stop - + if($Fields){ + $fields+=",summary,status,created" + $resourceURi = "$server/rest/api/latest/issue/{0}?fields='$Fields'expand=transitions" + } $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" $searchURi = "$server/rest/api/latest/search" } process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" switch ($PSCmdlet.ParameterSetName) { @@ -104,12 +113,18 @@ function Get-JiraIssue { foreach ($_key in $Key) { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_key]" Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_key [$_key]" - + #added if statment and $fields + $parameter = @{ + URI = $resourceURi -f $_key + Method = "GET" + Credential = $Credential + } $parameter = @{ URI = $resourceURi -f $_key Method = "GET" Credential = $Credential } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" $result = Invoke-JiraMethod @parameter From 1ec94127c14d231d8aa68383a572a9eafc321d68 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sat, 7 Jul 2018 14:46:31 -0500 Subject: [PATCH 02/29] byjql is working --- JiraPS/Public/Get-JiraIssue.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 775b8848..7c282e80 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -97,11 +97,15 @@ function Get-JiraIssue { $server = Get-JiraConfigServer -ErrorAction Stop if($Fields){ - $fields+=",summary,status,created" - $resourceURi = "$server/rest/api/latest/issue/{0}?fields='$Fields'expand=transitions" + $resourceURi = "$server/rest/api/latest/issue/{0}?fields='$Fields'all&expand=transitions" + $searchURi = "$server/rest/api/latest/search" + + } + else{ $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" $searchURi = "$server/rest/api/latest/search" + } } process { @@ -149,6 +153,8 @@ function Get-JiraIssue { validateQuery = $true expand = "transitions" maxResults = $PageSize + fields = $Fields + } OutputType = "JiraIssue" Paging = $true @@ -190,6 +196,7 @@ function Get-JiraIssue { OutputType = "JiraIssue" Paging = $true Credential = $Credential + Fields = $Fields } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { From f8b0bc72ff7929db7bd75f763cf7c7533fc7ce8e Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sat, 7 Jul 2018 15:42:56 -0500 Subject: [PATCH 03/29] byjql,issuekey,byfilter all functional with fields --- JiraPS/Public/Get-JiraIssue.ps1 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 7c282e80..d38db63d 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -96,15 +96,12 @@ function Get-JiraIssue { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" $server = Get-JiraConfigServer -ErrorAction Stop + $searchURi = "$server/rest/api/latest/search" if($Fields){ - $resourceURi = "$server/rest/api/latest/issue/{0}?fields='$Fields'all&expand=transitions" - $searchURi = "$server/rest/api/latest/search" - - + $resourceURi = "$server/rest/api/latest/issue/{0}?fields=$Fields&expand=transitions" } else{ $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" - $searchURi = "$server/rest/api/latest/search" } } @@ -122,6 +119,7 @@ function Get-JiraIssue { URI = $resourceURi -f $_key Method = "GET" Credential = $Credential + } $parameter = @{ URI = $resourceURi -f $_key @@ -179,14 +177,19 @@ function Get-JiraIssue { Invoke-JiraMethod @parameter } 'ByFilter' { - $filterObj = Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop + if($fields){ + $filterObj = (Get-JiraFilter -InputObject $Filter).searchurl.insert((Get-JiraFilter $Filter).searchurl.indexof('?')+1,"fields=$Fields&") + } + else { + + } <# #ToDo:CustomClass Once we have custom classes, this will no longer be necessary #> $parameter = @{ - URI = $filterObj.SearchUrl + URI = $filterObj Method = "GET" GetParameter = @{ validateQuery = $true @@ -196,7 +199,7 @@ function Get-JiraIssue { OutputType = "JiraIssue" Paging = $true Credential = $Credential - Fields = $Fields + } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { From ead3cc2ed51387ae466d71dd9895633b1a51bc44 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sat, 7 Jul 2018 15:45:05 -0500 Subject: [PATCH 04/29] byfilter was broken --- JiraPS/Public/Get-JiraIssue.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index d38db63d..caf7eadc 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -177,11 +177,11 @@ function Get-JiraIssue { Invoke-JiraMethod @parameter } 'ByFilter' { - if($fields){ + if($Fields){ $filterObj = (Get-JiraFilter -InputObject $Filter).searchurl.insert((Get-JiraFilter $Filter).searchurl.indexof('?')+1,"fields=$Fields&") } else { - + $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl } <# #ToDo:CustomClass From d8b97c622465a8516ca4bfb5ce77224d366d3879 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sat, 7 Jul 2018 17:15:13 -0500 Subject: [PATCH 05/29] updated docs and fixed line 109 (naume) --- JiraPS/Public/Get-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index caf7eadc..082207ab 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -106,7 +106,7 @@ function Get-JiraIssue { } process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" switch ($PSCmdlet.ParameterSetName) { From fd911431d3b8124f12bb30c65ddfb1e370ed78d9 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sat, 7 Jul 2018 18:08:57 -0500 Subject: [PATCH 06/29] added space in get-jiraissue.md --- docs/en-US/commands/Get-JiraIssue.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index 5a01c7c9..51687d34 100644 --- a/docs/en-US/commands/Get-JiraIssue.md +++ b/docs/en-US/commands/Get-JiraIssue.md @@ -18,7 +18,7 @@ Returns information about an issue in JIRA. ### ByIssueKey (Default) ```powershell -Get-JiraIssue [-Key] [-IncludeTotalCount] [-Skip ] [-First ] +Get-JiraIssue [-Key] [-Fields ][-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] ``` @@ -32,14 +32,14 @@ Get-JiraIssue [-InputObject] [-IncludeTotalCount] [-Skip ] [- ### ByJQL ```powershell -Get-JiraIssue -Query [-StartIndex ] [-MaxResults ] [[PageSize] ] +Get-JiraIssue -Query [-Fields ] [-StartIndex ] [-MaxResults ] [[PageSize] ] [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] ``` ### ByFilter ```powershell -Get-JiraIssue -Filter [-StartIndex ] [-MaxResults ] [[PageSize] ] +Get-JiraIssue -Filter [-Fields ][-StartIndex ] [-MaxResults ] [[PageSize] ] [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] ``` @@ -173,6 +173,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Fields + +Field you would like to select from your issue + +```yaml +Type: String[] +Parameter Sets: ByFilter +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -StartIndex > NOTE: This parameter has been marked as deprecated and will be removed with the next major release. From af52b8336e6dc2203077912e50ae85effc563fe4 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 8 Jul 2018 02:44:25 +0200 Subject: [PATCH 07/29] Improved documentation of -Fields parameter --- docs/en-US/commands/Get-JiraIssue.md | 45 +++++++++++++++++++++------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index 51687d34..f4b0f964 100644 --- a/docs/en-US/commands/Get-JiraIssue.md +++ b/docs/en-US/commands/Get-JiraIssue.md @@ -18,29 +18,31 @@ Returns information about an issue in JIRA. ### ByIssueKey (Default) ```powershell -Get-JiraIssue [-Key] [-Fields ][-IncludeTotalCount] [-Skip ] [-First ] - [-Credential ] [] +Get-JiraIssue [-Key] [-Fields ] [-IncludeTotalCount] + [-Skip ] [-First ] [-Credential ] [] ``` ### ByInputObject ```powershell -Get-JiraIssue [-InputObject] [-IncludeTotalCount] [-Skip ] [-First ] - [-Credential ] [] +Get-JiraIssue [-InputObject] [-Fields ] [-IncludeTotalCount] + [-Skip ] [-First ] [-Credential ] [] ``` ### ByJQL ```powershell -Get-JiraIssue -Query [-Fields ] [-StartIndex ] [-MaxResults ] [[PageSize] ] - [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] +Get-JiraIssue -Query [-Fields ] [-StartIndex ] +[-MaxResults ] [[PageSize] ] [-IncludeTotalCount] [-Skip ] + [-First ] [-Credential ] [] ``` ### ByFilter ```powershell -Get-JiraIssue -Filter [-Fields ][-StartIndex ] [-MaxResults ] [[PageSize] ] - [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] +Get-JiraIssue -Filter [-Fields ][-StartIndex ] + [-MaxResults ] [[PageSize] ] [-IncludeTotalCount] [-Skip ] + [-First ] [-Credential ] [] ``` ## DESCRIPTION @@ -102,11 +104,23 @@ This example retrieves all issues that match the criteria in the saved filter wi ### EXAMPLE 6 ```powershell -Get-JiraFilter 12345 | Select-Object * +Get-JiraFilter 12345 | Get-JiraIssue | Select-Object * ``` This prints all fields of the issue to the console. +### Example 7 + +```powershell +Get-JiraIssue -Query "project = TEST" -Fields "key", "summary", "assignee" +``` + +This example retrieves all issues in project "TEST" - but only the 3 properties +listed above: key, summary and assignee + +By retrieving only the data really needed, the payload the server sends is +reduced, which speeds up the query. + ## PARAMETERS ### -Key @@ -175,7 +189,16 @@ Accept wildcard characters: False ### -Fields -Field you would like to select from your issue +Field you would like to select from your issue. By default, all fields are +returned. + +Allowed values: + +- `"*all"` - return all fields. +- `"*navigable"` - return navigable fields only. +- `"summary", "comment"` - return the summary and comments fields only. +- `"-comment"` - return all fields except comments. +- `"*all", "-comment"` - same as above ```yaml Type: String[] @@ -184,7 +207,7 @@ Aliases: Required: False Position: Named -Default value: None +Default value: "*all" Accept pipeline input: False Accept wildcard characters: False ``` From 2ecf612c2e324a7742f69a52ad63415167a50836 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 8 Jul 2018 02:45:08 +0200 Subject: [PATCH 08/29] Cleaned up code Using `Invoke-JiraMethod`'s -GetParameter to simplify the URL of the API --- JiraPS/Public/Get-JiraIssue.ps1 | 57 ++++++++++++++++----------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 082207ab..29615967 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -7,12 +7,6 @@ function Get-JiraIssue { [Alias('Issue')] [String[]] $Key, - #added Fields Parameter - [Parameter(Mandatory=$false)] - [ValidateNotNullOrEmpty()] - [String[]] - $Fields, - [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] @@ -71,6 +65,11 @@ function Get-JiraIssue { [Object] $Filter, + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $Fields = "*all", + [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] [UInt32] @@ -96,17 +95,15 @@ function Get-JiraIssue { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" $server = Get-JiraConfigServer -ErrorAction Stop + $searchURi = "$server/rest/api/latest/search" - if($Fields){ - $resourceURi = "$server/rest/api/latest/issue/{0}?fields=$Fields&expand=transitions" - } - else{ - $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" - } + $resourceURi = "$server/rest/api/latest/issue/{0}" + + $Fields = $Fields -join "," } process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" switch ($PSCmdlet.ParameterSetName) { @@ -114,17 +111,17 @@ function Get-JiraIssue { foreach ($_key in $Key) { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_key]" Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_key [$_key]" - #added if statment and $fields - $parameter = @{ - URI = $resourceURi -f $_key - Method = "GET" - Credential = $Credential - } + $getParameter = @{ expand = "transitions" } + if ($Fields) { + $getParameter["fields"] = $Fields + } + $parameter = @{ - URI = $resourceURi -f $_key - Method = "GET" - Credential = $Credential + URI = $resourceURi -f $_key + Method = "GET" + GetParameter = $getParameter + Credential = $Credential } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" @@ -139,7 +136,7 @@ function Get-JiraIssue { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_issue [$_issue]" - Write-Output (Get-JiraIssue -Key $_issue.Key -Credential $Credential) + Write-Output (Get-JiraIssue -Key $_issue.Key -Fields $Fields -Credential $Credential) } } 'ByJQL' { @@ -151,13 +148,15 @@ function Get-JiraIssue { validateQuery = $true expand = "transitions" maxResults = $PageSize - fields = $Fields } OutputType = "JiraIssue" Paging = $true Credential = $Credential } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields + } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { $parameter[$_] = $PSCmdlet.PagingParameters.$_ @@ -177,12 +176,7 @@ function Get-JiraIssue { Invoke-JiraMethod @parameter } 'ByFilter' { - if($Fields){ - $filterObj = (Get-JiraFilter -InputObject $Filter).searchurl.insert((Get-JiraFilter $Filter).searchurl.indexof('?')+1,"fields=$Fields&") - } - else { - $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl - } + $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl <# #ToDo:CustomClass Once we have custom classes, this will no longer be necessary @@ -201,6 +195,9 @@ function Get-JiraIssue { Credential = $Credential } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields + } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { $parameter[$_] = $PSCmdlet.PagingParameters.$_ From 644587417621dfda8f315440929e01aa858607da Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sat, 7 Jul 2018 23:54:22 -0500 Subject: [PATCH 09/29] modifed $Fields = $Fields -join , --- JiraPS/Public/Get-JiraIssue.ps1 | 52 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 082207ab..a22cf723 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -7,12 +7,6 @@ function Get-JiraIssue { [Alias('Issue')] [String[]] $Key, - #added Fields Parameter - [Parameter(Mandatory=$false)] - [ValidateNotNullOrEmpty()] - [String[]] - $Fields, - [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] @@ -71,6 +65,11 @@ function Get-JiraIssue { [Object] $Filter, + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $Fields, + [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] [UInt32] @@ -96,17 +95,16 @@ function Get-JiraIssue { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" $server = Get-JiraConfigServer -ErrorAction Stop + $searchURi = "$server/rest/api/latest/search" + $resourceURi = "$server/rest/api/latest/issue/{0}" if($Fields){ - $resourceURi = "$server/rest/api/latest/issue/{0}?fields=$Fields&expand=transitions" - } - else{ - $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" + $Fields = $Fields -join "," } } process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" switch ($PSCmdlet.ParameterSetName) { @@ -114,17 +112,17 @@ function Get-JiraIssue { foreach ($_key in $Key) { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_key]" Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_key [$_key]" - #added if statment and $fields - $parameter = @{ - URI = $resourceURi -f $_key - Method = "GET" - Credential = $Credential - } + $getParameter = @{ expand = "transitions" } + if ($Fields) { + $getParameter["fields"] = $Fields + } + $parameter = @{ - URI = $resourceURi -f $_key - Method = "GET" - Credential = $Credential + URI = $resourceURi -f $_key + Method = "GET" + GetParameter = $getParameter + Credential = $Credential } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" @@ -151,13 +149,15 @@ function Get-JiraIssue { validateQuery = $true expand = "transitions" maxResults = $PageSize - fields = $Fields } OutputType = "JiraIssue" Paging = $true Credential = $Credential } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields + } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { $parameter[$_] = $PSCmdlet.PagingParameters.$_ @@ -177,12 +177,7 @@ function Get-JiraIssue { Invoke-JiraMethod @parameter } 'ByFilter' { - if($Fields){ - $filterObj = (Get-JiraFilter -InputObject $Filter).searchurl.insert((Get-JiraFilter $Filter).searchurl.indexof('?')+1,"fields=$Fields&") - } - else { - $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl - } + $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl <# #ToDo:CustomClass Once we have custom classes, this will no longer be necessary @@ -201,6 +196,9 @@ function Get-JiraIssue { Credential = $Credential } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields + } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { $parameter[$_] = $PSCmdlet.PagingParameters.$_ From 3d78204f2950dd4f05749b618b6127500b4ab57b Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 8 Jul 2018 14:14:02 +0200 Subject: [PATCH 10/29] Fixed casting of String[] when parameter -Fields is left empty --- JiraPS/Public/Get-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 29615967..1b0ed72b 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -99,7 +99,7 @@ function Get-JiraIssue { $searchURi = "$server/rest/api/latest/search" $resourceURi = "$server/rest/api/latest/issue/{0}" - $Fields = $Fields -join "," + [String]$Fields = $Fields -join "," } process { From f6fa0ad2d71e5a3cd8e6499dbc142c1a612cb4c1 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sun, 8 Jul 2018 07:33:27 -0500 Subject: [PATCH 11/29] removing un from write-debugmessage --- JiraPS/Public/Get-JiraIssue.ps1 | 2 +- docs/en-US/commands/Get-JiraIssue.md | 578 +++++++++++---------------- 2 files changed, 225 insertions(+), 355 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index a22cf723..0487ef21 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -104,7 +104,7 @@ function Get-JiraIssue { } process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" switch ($PSCmdlet.ParameterSetName) { diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index 51687d34..7697bf16 100644 --- a/docs/en-US/commands/Get-JiraIssue.md +++ b/docs/en-US/commands/Get-JiraIssue.md @@ -1,354 +1,224 @@ ---- -external help file: JiraPS-help.xml -Module Name: JiraPS -online version: https://atlassianps.org/docs/JiraPS/commands/Get-JiraIssue/ -locale: en-US -schema: 2.0.0 -layout: documentation -permalink: /docs/JiraPS/commands/Get-JiraIssue/ ---- -# Get-JiraIssue - -## SYNOPSIS - -Returns information about an issue in JIRA. - -## SYNTAX - -### ByIssueKey (Default) - -```powershell -Get-JiraIssue [-Key] [-Fields ][-IncludeTotalCount] [-Skip ] [-First ] - [-Credential ] [] -``` - -### ByInputObject - -```powershell -Get-JiraIssue [-InputObject] [-IncludeTotalCount] [-Skip ] [-First ] - [-Credential ] [] -``` - -### ByJQL - -```powershell -Get-JiraIssue -Query [-Fields ] [-StartIndex ] [-MaxResults ] [[PageSize] ] - [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] -``` - -### ByFilter - -```powershell -Get-JiraIssue -Filter [-Fields ][-StartIndex ] [-MaxResults ] [[PageSize] ] - [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] -``` - -## DESCRIPTION - -This function retrieves the data of a issue 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). - -> For more details on JQL syntax, see this article from Atlassian: [https://confluence.atlassian.com/display/JIRA/Advanced+Searching](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`. - -## EXAMPLES - -### EXAMPLE 1 - -```powershell -Get-JiraIssue -Key TEST-001 -``` - -This example fetches the issue "TEST-001". - -The default `Format-Table` view of a Jira issue only shows the value of "Key", "Summary", "Status" and "Created". -> This can be manipulated with `Format-Table`, `Format-List` and `Select-Object` - -### EXAMPLE 2 - -```powershell -Get-JiraIssue "TEST-002" | Add-JiraIssueComment "Test comment from PowerShell" -``` - -This example illustrates pipeline use from `Get-JiraIssue` to `Add-JiraIssueComment`. - -### EXAMPLE 3 - -```powershell -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 4 - -```powershell -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 5 - -```powershell -Get-JiraFilter -Id 12345 | Get-JiraIssue -``` - -This example retrieves all issues that match the criteria in the saved filter with id 12345. - -### EXAMPLE 6 - -```powershell -Get-JiraFilter 12345 | Select-Object * -``` - -This prints all fields of the issue to the console. - -## PARAMETERS - -### -Key - -Key of the issue to search for. - -```yaml -Type: String[] -Parameter Sets: ByIssueKey -Aliases: - -Required: True -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -InputObject - -Object of an issue to search for. - -```yaml -Type: Object[] -Parameter Sets: ByInputObject -Aliases: - -Required: True -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Query - -JQL query for which to search for. - -```yaml -Type: String -Parameter Sets: ByJQL -Aliases: JQL - -Required: True -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Filter - -Object of an existing JIRA filter from which the results will be returned. - -```yaml -Type: Object -Parameter Sets: ByFilter -Aliases: - -Required: True -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Fields - -Field you would like to select from your issue - -```yaml -Type: String[] -Parameter Sets: ByFilter -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -StartIndex - -> NOTE: This parameter has been marked as deprecated and will be removed with the next major release. -> Use `-Skip` instead. - -Index of the first issue to return. - -This can be used to "page" through issues in a large collection or a slow connection. - -```yaml -Type: UInt32 -Parameter Sets: ByJQL, ByFilter -Aliases: - -Required: False -Position: Named -Default value: 0 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -MaxResults - -> NOTE: This parameter has been marked as deprecated and will be removed with the next major release. -> Use `-First` instead. - -Maximum number of results to return. - -By default, all issues will be returned. - -```yaml -Type: UInt32 -Parameter Sets: ByJQL, ByFilter -Aliases: - -Required: False -Position: Named -Default value: 0 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -PageSize - -How many issues should be returned per call to JIRA. - -This parameter only has effect if `-MaxResults` is not provided or set to 0. - -Normally, you should not need to adjust this parameter, -but if the REST calls take a long time, -try playing with different values here. - -```yaml -Type: UInt32 -Parameter Sets: ByJQL, ByFilter -Aliases: - -Required: False -Position: Named -Default value: 25 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -IncludeTotalCount - -Causes an extra output of the total count at the beginning. - -Note this is actually a uInt64, but with a custom string representation. - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Skip - -Controls how many things will be skipped before starting output. - -Defaults to 0. - -```yaml -Type: UInt64 -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: 0 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -First - -Indicates how many items to return. - -```yaml -Type: UInt64 -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: 18446744073709551615 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Credential - -Credentials to use to connect to JIRA. -If not specified, this function will use anonymous access. - -```yaml -Type: PSCredential -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. -For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### [JiraPS.Issue] / [String] - -- If a JiraPS.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 - -### [JiraPS.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. - -## RELATED LINKS - -[about_JiraPS_CreatingIssues](../../about/creating-issues.html) - -[about_JiraPS_CustomFields](../../about/custom-fields.html) - -[New-JiraIssue](../New-JiraIssue/) +function Get-JiraIssue { + # .ExternalHelp ..\JiraPS-help.xml + [CmdletBinding( SupportsPaging, DefaultParameterSetName = 'ByIssueKey' )] + param( + [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByIssueKey' )] + [ValidateNotNullOrEmpty()] + [Alias('Issue')] + [String[]] + $Key, + + [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByInputObject' )] + [ValidateNotNullOrEmpty()] + [ValidateScript( + { + if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraIssue' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget + $errorItem.ErrorDetails = "Wrong object type provided for Issue. Expected [JiraPS.Issue] or [String], but was $($_.GetType().Name)" + $PSCmdlet.ThrowTerminatingError($errorItem) + } + else { + return $true + } + } + )] + [Object[]] + $InputObject, + <# + #ToDo:Deprecate + This is not necessary if $Key uses ValueFromPipelineByPropertyName + #ToDo:CustomClass + Once we have custom classes, this check can be done with Type declaration + #> + + [Parameter( Mandatory, ParameterSetName = 'ByJQL' )] + [Alias('JQL')] + [String] + $Query, + + [Parameter( Mandatory, ParameterSetName = 'ByFilter' )] + [ValidateNotNullOrEmpty()] + [ValidateScript( + { + if (("JiraPS.Filter" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraFilter' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget + $errorItem.ErrorDetails = "Wrong object type provided for Filter. Expected [JiraPS.Filter] or [String], but was $($_.GetType().Name)" + $PSCmdlet.ThrowTerminatingError($errorItem) + <# + #ToDo:CustomClass + Once we have custom classes, this check can be done with Type declaration + #> + } + else { + return $true + } + } + )] + [Object] + $Filter, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $Fields, + + [Parameter( ParameterSetName = 'ByJQL' )] + [Parameter( ParameterSetName = 'ByFilter' )] + [UInt32] + $StartIndex = 0, + + [Parameter( ParameterSetName = 'ByJQL' )] + [Parameter( ParameterSetName = 'ByFilter' )] + [UInt32] + $MaxResults = 0, + + [Parameter( ParameterSetName = 'ByJQL' )] + [Parameter( ParameterSetName = 'ByFilter' )] + [UInt32] + $PageSize = $script:DefaultPageSize, + + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty + ) + + begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + + $server = Get-JiraConfigServer -ErrorAction Stop + + $searchURi = "$server/rest/api/latest/search" + $resourceURi = "$server/rest/api/latest/issue/{0}" + + $Fields = $Fields -join "," + } + + process { + Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + switch ($PSCmdlet.ParameterSetName) { + 'ByIssueKey' { + foreach ($_key in $Key) { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_key]" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_key [$_key]" + + $getParameter = @{ expand = "transitions" } + if ($Fields) { + $getParameter["fields"] = $Fields + } + + $parameter = @{ + URI = $resourceURi -f $_key + Method = "GET" + GetParameter = $getParameter + Credential = $Credential + } + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraIssue -InputObject $result) + } + } + 'ByInputObject' { + # Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-InputObject' has been marked as deprecated." + foreach ($_issue in $InputObject) { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_issue [$_issue]" + + Write-Output (Get-JiraIssue -Key $_issue.Key -Credential $Credential) + } + } + 'ByJQL' { + $parameter = @{ + URI = $searchURi + Method = "GET" + GetParameter = @{ + jql = (ConvertTo-URLEncoded $Query) + validateQuery = $true + expand = "transitions" + maxResults = $PageSize + + } + OutputType = "JiraIssue" + Paging = $true + Credential = $Credential + } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields + } + # Paging + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $parameter[$_] = $PSCmdlet.PagingParameters.$_ + } + # Make `SupportsPaging` be backwards compatible + if ($StartIndex) { + Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-StartIndex' has been marked as deprecated. For more information, plase read the help." + $parameter["Skip"] = $StartIndex + } + if ($MaxResults) { + Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-MaxResults' has been marked as deprecated. For more information, plase read the help." + $parameter["First"] = $MaxResults + } + + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter + } + 'ByFilter' { + $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl + <# + #ToDo:CustomClass + Once we have custom classes, this will no longer be necessary + #> + + $parameter = @{ + URI = $filterObj + Method = "GET" + GetParameter = @{ + validateQuery = $true + expand = "transitions" + maxResults = $PageSize + } + OutputType = "JiraIssue" + Paging = $true + Credential = $Credential + + } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields + } + # Paging + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $parameter[$_] = $PSCmdlet.PagingParameters.$_ + } + # Make `SupportsPaging` be backwards compatible + if ($StartIndex) { + Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-StartIndex' has been marked as deprecated. For more information, plase read the help." + $parameter["Skip"] = $StartIndex + } + if ($MaxResults) { + Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-MaxResults' has been marked as deprecated. For more information, plase read the help." + $parameter["First"] = $MaxResults + } + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter + } + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} From d315a6181aacb43c196b1814bae235da33858501 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sun, 8 Jul 2018 07:40:06 -0500 Subject: [PATCH 12/29] updated documentation --- docs/en-US/commands/Get-JiraIssue.md | 578 ++++++++++++++++----------- 1 file changed, 354 insertions(+), 224 deletions(-) diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index 7697bf16..51687d34 100644 --- a/docs/en-US/commands/Get-JiraIssue.md +++ b/docs/en-US/commands/Get-JiraIssue.md @@ -1,224 +1,354 @@ -function Get-JiraIssue { - # .ExternalHelp ..\JiraPS-help.xml - [CmdletBinding( SupportsPaging, DefaultParameterSetName = 'ByIssueKey' )] - param( - [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByIssueKey' )] - [ValidateNotNullOrEmpty()] - [Alias('Issue')] - [String[]] - $Key, - - [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByInputObject' )] - [ValidateNotNullOrEmpty()] - [ValidateScript( - { - if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] - $errorId = 'ParameterType.NotJiraIssue' - $errorCategory = 'InvalidArgument' - $errorTarget = $_ - $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget - $errorItem.ErrorDetails = "Wrong object type provided for Issue. Expected [JiraPS.Issue] or [String], but was $($_.GetType().Name)" - $PSCmdlet.ThrowTerminatingError($errorItem) - } - else { - return $true - } - } - )] - [Object[]] - $InputObject, - <# - #ToDo:Deprecate - This is not necessary if $Key uses ValueFromPipelineByPropertyName - #ToDo:CustomClass - Once we have custom classes, this check can be done with Type declaration - #> - - [Parameter( Mandatory, ParameterSetName = 'ByJQL' )] - [Alias('JQL')] - [String] - $Query, - - [Parameter( Mandatory, ParameterSetName = 'ByFilter' )] - [ValidateNotNullOrEmpty()] - [ValidateScript( - { - if (("JiraPS.Filter" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] - $errorId = 'ParameterType.NotJiraFilter' - $errorCategory = 'InvalidArgument' - $errorTarget = $_ - $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget - $errorItem.ErrorDetails = "Wrong object type provided for Filter. Expected [JiraPS.Filter] or [String], but was $($_.GetType().Name)" - $PSCmdlet.ThrowTerminatingError($errorItem) - <# - #ToDo:CustomClass - Once we have custom classes, this check can be done with Type declaration - #> - } - else { - return $true - } - } - )] - [Object] - $Filter, - - [Parameter()] - [ValidateNotNullOrEmpty()] - [String[]] - $Fields, - - [Parameter( ParameterSetName = 'ByJQL' )] - [Parameter( ParameterSetName = 'ByFilter' )] - [UInt32] - $StartIndex = 0, - - [Parameter( ParameterSetName = 'ByJQL' )] - [Parameter( ParameterSetName = 'ByFilter' )] - [UInt32] - $MaxResults = 0, - - [Parameter( ParameterSetName = 'ByJQL' )] - [Parameter( ParameterSetName = 'ByFilter' )] - [UInt32] - $PageSize = $script:DefaultPageSize, - - [Parameter()] - [System.Management.Automation.PSCredential] - [System.Management.Automation.Credential()] - $Credential = [System.Management.Automation.PSCredential]::Empty - ) - - begin { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" - - $server = Get-JiraConfigServer -ErrorAction Stop - - $searchURi = "$server/rest/api/latest/search" - $resourceURi = "$server/rest/api/latest/issue/{0}" - - $Fields = $Fields -join "," - } - - process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" - - switch ($PSCmdlet.ParameterSetName) { - 'ByIssueKey' { - foreach ($_key in $Key) { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_key]" - Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_key [$_key]" - - $getParameter = @{ expand = "transitions" } - if ($Fields) { - $getParameter["fields"] = $Fields - } - - $parameter = @{ - URI = $resourceURi -f $_key - Method = "GET" - GetParameter = $getParameter - Credential = $Credential - } - - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - $result = Invoke-JiraMethod @parameter - - Write-Output (ConvertTo-JiraIssue -InputObject $result) - } - } - 'ByInputObject' { - # Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-InputObject' has been marked as deprecated." - foreach ($_issue in $InputObject) { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" - Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_issue [$_issue]" - - Write-Output (Get-JiraIssue -Key $_issue.Key -Credential $Credential) - } - } - 'ByJQL' { - $parameter = @{ - URI = $searchURi - Method = "GET" - GetParameter = @{ - jql = (ConvertTo-URLEncoded $Query) - validateQuery = $true - expand = "transitions" - maxResults = $PageSize - - } - OutputType = "JiraIssue" - Paging = $true - Credential = $Credential - } - if ($Fields) { - $parameter["GetParameter"]["fields"] = $Fields - } - # Paging - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { - $parameter[$_] = $PSCmdlet.PagingParameters.$_ - } - # Make `SupportsPaging` be backwards compatible - if ($StartIndex) { - Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-StartIndex' has been marked as deprecated. For more information, plase read the help." - $parameter["Skip"] = $StartIndex - } - if ($MaxResults) { - Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-MaxResults' has been marked as deprecated. For more information, plase read the help." - $parameter["First"] = $MaxResults - } - - - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - Invoke-JiraMethod @parameter - } - 'ByFilter' { - $filterObj = (Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop).searchurl - <# - #ToDo:CustomClass - Once we have custom classes, this will no longer be necessary - #> - - $parameter = @{ - URI = $filterObj - Method = "GET" - GetParameter = @{ - validateQuery = $true - expand = "transitions" - maxResults = $PageSize - } - OutputType = "JiraIssue" - Paging = $true - Credential = $Credential - - } - if ($Fields) { - $parameter["GetParameter"]["fields"] = $Fields - } - # Paging - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { - $parameter[$_] = $PSCmdlet.PagingParameters.$_ - } - # Make `SupportsPaging` be backwards compatible - if ($StartIndex) { - Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-StartIndex' has been marked as deprecated. For more information, plase read the help." - $parameter["Skip"] = $StartIndex - } - if ($MaxResults) { - Write-Warning "[$($MyInvocation.MyCommand.Name)] The parameter '-MaxResults' has been marked as deprecated. For more information, plase read the help." - $parameter["First"] = $MaxResults - } - - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - Invoke-JiraMethod @parameter - } - } - } - - end { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" - } -} +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/Get-JiraIssue/ +locale: en-US +schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Get-JiraIssue/ +--- +# Get-JiraIssue + +## SYNOPSIS + +Returns information about an issue in JIRA. + +## SYNTAX + +### ByIssueKey (Default) + +```powershell +Get-JiraIssue [-Key] [-Fields ][-IncludeTotalCount] [-Skip ] [-First ] + [-Credential ] [] +``` + +### ByInputObject + +```powershell +Get-JiraIssue [-InputObject] [-IncludeTotalCount] [-Skip ] [-First ] + [-Credential ] [] +``` + +### ByJQL + +```powershell +Get-JiraIssue -Query [-Fields ] [-StartIndex ] [-MaxResults ] [[PageSize] ] + [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] +``` + +### ByFilter + +```powershell +Get-JiraIssue -Filter [-Fields ][-StartIndex ] [-MaxResults ] [[PageSize] ] + [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] +``` + +## DESCRIPTION + +This function retrieves the data of a issue 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). + +> For more details on JQL syntax, see this article from Atlassian: [https://confluence.atlassian.com/display/JIRA/Advanced+Searching](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`. + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +Get-JiraIssue -Key TEST-001 +``` + +This example fetches the issue "TEST-001". + +The default `Format-Table` view of a Jira issue only shows the value of "Key", "Summary", "Status" and "Created". +> This can be manipulated with `Format-Table`, `Format-List` and `Select-Object` + +### EXAMPLE 2 + +```powershell +Get-JiraIssue "TEST-002" | Add-JiraIssueComment "Test comment from PowerShell" +``` + +This example illustrates pipeline use from `Get-JiraIssue` to `Add-JiraIssueComment`. + +### EXAMPLE 3 + +```powershell +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 4 + +```powershell +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 5 + +```powershell +Get-JiraFilter -Id 12345 | Get-JiraIssue +``` + +This example retrieves all issues that match the criteria in the saved filter with id 12345. + +### EXAMPLE 6 + +```powershell +Get-JiraFilter 12345 | Select-Object * +``` + +This prints all fields of the issue to the console. + +## PARAMETERS + +### -Key + +Key of the issue to search for. + +```yaml +Type: String[] +Parameter Sets: ByIssueKey +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -InputObject + +Object of an issue to search for. + +```yaml +Type: Object[] +Parameter Sets: ByInputObject +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Query + +JQL query for which to search for. + +```yaml +Type: String +Parameter Sets: ByJQL +Aliases: JQL + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Filter + +Object of an existing JIRA filter from which the results will be returned. + +```yaml +Type: Object +Parameter Sets: ByFilter +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Fields + +Field you would like to select from your issue + +```yaml +Type: String[] +Parameter Sets: ByFilter +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -StartIndex + +> NOTE: This parameter has been marked as deprecated and will be removed with the next major release. +> Use `-Skip` instead. + +Index of the first issue to return. + +This can be used to "page" through issues in a large collection or a slow connection. + +```yaml +Type: UInt32 +Parameter Sets: ByJQL, ByFilter +Aliases: + +Required: False +Position: Named +Default value: 0 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -MaxResults + +> NOTE: This parameter has been marked as deprecated and will be removed with the next major release. +> Use `-First` instead. + +Maximum number of results to return. + +By default, all issues will be returned. + +```yaml +Type: UInt32 +Parameter Sets: ByJQL, ByFilter +Aliases: + +Required: False +Position: Named +Default value: 0 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PageSize + +How many issues should be returned per call to JIRA. + +This parameter only has effect if `-MaxResults` is not provided or set to 0. + +Normally, you should not need to adjust this parameter, +but if the REST calls take a long time, +try playing with different values here. + +```yaml +Type: UInt32 +Parameter Sets: ByJQL, ByFilter +Aliases: + +Required: False +Position: Named +Default value: 25 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -IncludeTotalCount + +Causes an extra output of the total count at the beginning. + +Note this is actually a uInt64, but with a custom string representation. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Skip + +Controls how many things will be skipped before starting output. + +Defaults to 0. + +```yaml +Type: UInt64 +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: 0 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -First + +Indicates how many items to return. + +```yaml +Type: UInt64 +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: 18446744073709551615 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Credential + +Credentials to use to connect to JIRA. +If not specified, this function will use anonymous access. + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### [JiraPS.Issue] / [String] + +- If a JiraPS.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 + +### [JiraPS.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. + +## RELATED LINKS + +[about_JiraPS_CreatingIssues](../../about/creating-issues.html) + +[about_JiraPS_CustomFields](../../about/custom-fields.html) + +[New-JiraIssue](../New-JiraIssue/) From 33da44c3bb9960574b688474cf6745c0f2a524f9 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 8 Jul 2018 14:41:50 +0200 Subject: [PATCH 13/29] Fixed name of the function in debug messages --- JiraPS/Public/Get-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 1b0ed72b..ae208d0c 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -103,7 +103,7 @@ function Get-JiraIssue { } process { - Write-DebugMessage "[$($MyInvocation.MyCommand.Namune)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" switch ($PSCmdlet.ParameterSetName) { From 15badd102b52a7b0d4b3581819d1a4d97f555370 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 8 Jul 2018 14:42:07 +0200 Subject: [PATCH 14/29] Added Unit Tests for -Fields --- Tests/Get-JiraIssue.Tests.ps1 | 131 +++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 19 deletions(-) diff --git a/Tests/Get-JiraIssue.Tests.ps1 b/Tests/Get-JiraIssue.Tests.ps1 index 8ecd54fc..dfbb9aee 100644 --- a/Tests/Get-JiraIssue.Tests.ps1 +++ b/Tests/Get-JiraIssue.Tests.ps1 @@ -1,6 +1,8 @@ Describe "Get-JiraIssue" { - - Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } InModuleScope JiraPS { @@ -28,31 +30,54 @@ '@ #region Mocks - Mock Get-JiraConfigServer { + Mock Get-JiraConfigServer -ModuleName JiraPS { $jiraServer } - Mock Invoke-JiraMethod -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/issue/TEST-001*" } { + Mock Get-JiraUser -ModuleName JiraPS { + $object = [PSCustomObject] @{ + 'Name' = 'username' + } + $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') + return $object + } + + Mock Get-JiraFilter -ModuleName JiraPS { + [PSCustomObject]@{ + PSTypeName = "JiraPS.Filter" + Id = 12345 + SearchUrl = "https://jira.example.com/rest/api/latest/filter/12345" + } + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/rest/api/*/issue/TEST-001*" + } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $response } - Mock Invoke-JiraMethod -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/search" -and $GetParameter["jql"] -eq $jqlEscaped } { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/rest/api/*/search" -and + $GetParameter["jql"] -eq $jqlEscaped + } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $response } - Mock Invoke-JiraMethod { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/rest/api/*/filter/*" + } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - throw "Unidentified call to Invoke-JiraMethod" + ConvertFrom-Json $response } - Mock Get-JiraUser { - $object = [PSCustomObject] @{ - 'Name' = 'username' - } - $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') - return $object + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" } #endregion Mocks @@ -63,6 +88,7 @@ defParam $command 'InputObject' defParam $command 'Query' defParam $command 'Filter' + defParam $command 'Fields' defParam $command 'StartIndex' defParam $command 'MaxResults' defParam $command 'PageSize' @@ -72,7 +98,7 @@ Context "Behavior testing" { It "Obtains information about a provided issue in JIRA" { - { Get-JiraIssue -Key TEST-001 } | Should Not Throw + { Get-JiraIssue -Key TEST-001 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -89,7 +115,7 @@ } It "Uses JQL to search for issues if the -Query parameter is used" { - { Get-JiraIssue -Query $jql } | Should Not Throw + { Get-JiraIssue -Query $jql } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -107,7 +133,7 @@ } It "Supports the -StartIndex and -MaxResults parameters to page through search results" { - { Get-JiraIssue -Query $jql -StartIndex 10 -MaxResults 50 } | Should Not Throw + { Get-JiraIssue -Query $jql -StartIndex 10 -MaxResults 50 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -127,7 +153,7 @@ } It "Returns all issues via looping if -MaxResults is not specified" { - { Get-JiraIssue -Query $jql -PageSize 25 } | Should Not Throw + { Get-JiraIssue -Query $jql -PageSize 25 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -144,11 +170,78 @@ } Assert-MockCalled @assertMockCalledSplat } + + It "Returns only the fields required with -Fields" { + $issue = [PSCustomObject]@{ + PSTypeName = "JiraPS.Issue" + Key = "TEST-001" + } + + { Get-JiraIssue -Key TEST-001 } | Should -Not -Throw + { Get-JiraIssue -Key TEST-001 -Fields "key" } | Should -Not -Throw + { Get-JiraIssue -Key TEST-001 -Fields "-summary" } | Should -Not -Throw + { Get-JiraIssue -Key TEST-001 -Fields "key", "summary", "status" } | Should -Not -Throw + { Get-JiraIssue -InputObject $issue -Fields "key", "summary", "status" } | Should -Not -Throw + { Get-JiraIssue -Query $jql -Fields "key", "summary", "status" } | Should -Not -Throw + { Get-JiraIssue -Filter "12345" -Fields "key", "summary", "status" } | Should -Not -Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "*all" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "key" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "-summary" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "key,summary,status" + } + Scope = 'It' + Exactly = $true + Times = 4 + } + Assert-MockCalled @assertMockCalledSplat + } } Context "Input testing" { It "Accepts an issue key for the -Key parameter" { - { Get-JiraIssue -Key TEST-001 } | Should Not Throw + { Get-JiraIssue -Key TEST-001 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -172,7 +265,7 @@ $issue.PSObject.TypeNames.Insert(0, 'JiraPS.Issue') # Should call Get-JiraIssue using the -Key parameter, so our URL should reflect the key we provided - { Get-JiraIssue -InputObject $Issue } | Should Not Throw + { Get-JiraIssue -InputObject $Issue } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' From f9313fe8b76139f3d88e71ef9c3ab040c3f14362 Mon Sep 17 00:00:00 2001 From: Phillip Guzman Date: Sun, 8 Jul 2018 07:47:12 -0500 Subject: [PATCH 15/29] updating tests --- Tests/Get-JiraIssue.Tests.ps1 | 131 +++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 19 deletions(-) diff --git a/Tests/Get-JiraIssue.Tests.ps1 b/Tests/Get-JiraIssue.Tests.ps1 index 8ecd54fc..dfbb9aee 100644 --- a/Tests/Get-JiraIssue.Tests.ps1 +++ b/Tests/Get-JiraIssue.Tests.ps1 @@ -1,6 +1,8 @@ Describe "Get-JiraIssue" { - - Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } InModuleScope JiraPS { @@ -28,31 +30,54 @@ '@ #region Mocks - Mock Get-JiraConfigServer { + Mock Get-JiraConfigServer -ModuleName JiraPS { $jiraServer } - Mock Invoke-JiraMethod -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/issue/TEST-001*" } { + Mock Get-JiraUser -ModuleName JiraPS { + $object = [PSCustomObject] @{ + 'Name' = 'username' + } + $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') + return $object + } + + Mock Get-JiraFilter -ModuleName JiraPS { + [PSCustomObject]@{ + PSTypeName = "JiraPS.Filter" + Id = 12345 + SearchUrl = "https://jira.example.com/rest/api/latest/filter/12345" + } + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/rest/api/*/issue/TEST-001*" + } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $response } - Mock Invoke-JiraMethod -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/search" -and $GetParameter["jql"] -eq $jqlEscaped } { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/rest/api/*/search" -and + $GetParameter["jql"] -eq $jqlEscaped + } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $response } - Mock Invoke-JiraMethod { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/rest/api/*/filter/*" + } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - throw "Unidentified call to Invoke-JiraMethod" + ConvertFrom-Json $response } - Mock Get-JiraUser { - $object = [PSCustomObject] @{ - 'Name' = 'username' - } - $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') - return $object + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" } #endregion Mocks @@ -63,6 +88,7 @@ defParam $command 'InputObject' defParam $command 'Query' defParam $command 'Filter' + defParam $command 'Fields' defParam $command 'StartIndex' defParam $command 'MaxResults' defParam $command 'PageSize' @@ -72,7 +98,7 @@ Context "Behavior testing" { It "Obtains information about a provided issue in JIRA" { - { Get-JiraIssue -Key TEST-001 } | Should Not Throw + { Get-JiraIssue -Key TEST-001 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -89,7 +115,7 @@ } It "Uses JQL to search for issues if the -Query parameter is used" { - { Get-JiraIssue -Query $jql } | Should Not Throw + { Get-JiraIssue -Query $jql } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -107,7 +133,7 @@ } It "Supports the -StartIndex and -MaxResults parameters to page through search results" { - { Get-JiraIssue -Query $jql -StartIndex 10 -MaxResults 50 } | Should Not Throw + { Get-JiraIssue -Query $jql -StartIndex 10 -MaxResults 50 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -127,7 +153,7 @@ } It "Returns all issues via looping if -MaxResults is not specified" { - { Get-JiraIssue -Query $jql -PageSize 25 } | Should Not Throw + { Get-JiraIssue -Query $jql -PageSize 25 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -144,11 +170,78 @@ } Assert-MockCalled @assertMockCalledSplat } + + It "Returns only the fields required with -Fields" { + $issue = [PSCustomObject]@{ + PSTypeName = "JiraPS.Issue" + Key = "TEST-001" + } + + { Get-JiraIssue -Key TEST-001 } | Should -Not -Throw + { Get-JiraIssue -Key TEST-001 -Fields "key" } | Should -Not -Throw + { Get-JiraIssue -Key TEST-001 -Fields "-summary" } | Should -Not -Throw + { Get-JiraIssue -Key TEST-001 -Fields "key", "summary", "status" } | Should -Not -Throw + { Get-JiraIssue -InputObject $issue -Fields "key", "summary", "status" } | Should -Not -Throw + { Get-JiraIssue -Query $jql -Fields "key", "summary", "status" } | Should -Not -Throw + { Get-JiraIssue -Filter "12345" -Fields "key", "summary", "status" } | Should -Not -Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "*all" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "key" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "-summary" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $GetParameter["fields"] -eq "key,summary,status" + } + Scope = 'It' + Exactly = $true + Times = 4 + } + Assert-MockCalled @assertMockCalledSplat + } } Context "Input testing" { It "Accepts an issue key for the -Key parameter" { - { Get-JiraIssue -Key TEST-001 } | Should Not Throw + { Get-JiraIssue -Key TEST-001 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -172,7 +265,7 @@ $issue.PSObject.TypeNames.Insert(0, 'JiraPS.Issue') # Should call Get-JiraIssue using the -Key parameter, so our URL should reflect the key we provided - { Get-JiraIssue -InputObject $Issue } | Should Not Throw + { Get-JiraIssue -InputObject $Issue } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' From 57378c8d6772c44c7fc95575f4002068c7afd926 Mon Sep 17 00:00:00 2001 From: Conor Tolan Date: Fri, 21 Sep 2018 21:57:13 +0100 Subject: [PATCH 16/29] Fixed issue with params from pipeline. Issue was due to begin and end blocks using params. Added test for params from pipeline. --- JiraPS/Public/New-JiraIssue.ps1 | 22 +++++++++++++++------- Tests/New-JiraIssue.Tests.ps1 | 9 +++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/JiraPS/Public/New-JiraIssue.ps1 b/JiraPS/Public/New-JiraIssue.ps1 index 717b6e07..1e04f668 100644 --- a/JiraPS/Public/New-JiraIssue.ps1 +++ b/JiraPS/Public/New-JiraIssue.ps1 @@ -2,49 +2,59 @@ function New-JiraIssue { # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( - [Parameter( Mandatory )] + [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [String] $Project, - [Parameter( Mandatory )] + [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [String] $IssueType, - [Parameter( Mandatory )] + [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [String] $Summary, + [Parameter( ValueFromPipelineByPropertyName )] [Int] $Priority, + [Parameter( ValueFromPipelineByPropertyName )] [String] $Description, + [Parameter( ValueFromPipelineByPropertyName )] [AllowNull()] [AllowEmptyString()] [String] $Reporter, + [Parameter( ValueFromPipelineByPropertyName )] [String[]] $Labels, + [Parameter( ValueFromPipelineByPropertyName )] [String] $Parent, + [Parameter( ValueFromPipelineByPropertyName )] [Alias('FixVersions')] [String[]] $FixVersion, + [Parameter( ValueFromPipelineByPropertyName )] [PSCustomObject] $Fields, - [Parameter()] + [Parameter( ValueFromPipelineByPropertyName )] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { + } + + process { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" $server = Get-JiraConfigServer -ErrorAction Stop -Debug:$false @@ -52,9 +62,7 @@ function New-JiraIssue { $createmeta = Get-JiraIssueCreateMetadata -Project $Project -IssueType $IssueType -Credential $Credential -ErrorAction Stop -Debug:$false $resourceURi = "$server/rest/api/latest/issue" - } - process { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" @@ -161,9 +169,9 @@ function New-JiraIssue { # This will fetch the created issue to return it with all it'a properties Write-Output (Get-JiraIssue -Key $result.Key -Credential $Credential) } + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" } end { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" } } diff --git a/Tests/New-JiraIssue.Tests.ps1 b/Tests/New-JiraIssue.Tests.ps1 index 93acf18f..d0df80a2 100644 --- a/Tests/New-JiraIssue.Tests.ps1 +++ b/Tests/New-JiraIssue.Tests.ps1 @@ -80,6 +80,8 @@ 'Description' = 'Test description'; } + $pipelineParams = New-Object -TypeName PSCustomObject -Property $newParams + Context "Sanity checking" { $command = Get-Command -Name New-JiraIssue @@ -102,6 +104,13 @@ # including the summary provided in the test call above. Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "$jiraServer/rest/api/*/issue" } } + It "Creates an issue in JIRA from pipeline" { + { $pipelineParams | New-JiraIssue } | Should Not Throw + # The String in the ParameterFilter is made from the keywords + # we should expect to see in the JSON that should be sent, + # including the summary provided in the test call above. + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and $URI -like "$jiraServer/rest/api/*/issue" } + } } Context "Input testing" { From c01061f2171f8401bd4e8d80154a87e94c85c439 Mon Sep 17 00:00:00 2001 From: Conor Tolan Date: Fri, 21 Sep 2018 22:14:11 +0100 Subject: [PATCH 17/29] Added example showing how to pass multiple new issues via a object. --- docs/en-US/commands/New-JiraIssue.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/en-US/commands/New-JiraIssue.md b/docs/en-US/commands/New-JiraIssue.md index 264fb4e6..775e880e 100644 --- a/docs/en-US/commands/New-JiraIssue.md +++ b/docs/en-US/commands/New-JiraIssue.md @@ -82,6 +82,16 @@ This illustrates how to use splatting for the example above. Read more about splatting: about_Splatting +### EXAMPLE 4 + +```powershell +"project,summary,assignee,IssueType,Priority,Description" > "./data.csv" +"CS,Some Title 1,admin,Minor,1,Some Description 1" >> "./data.csv" +"CS,Some Title 2,admin,Minor,1,Some Description 2" >> "./data.csv" +import-csv "./data.csv" | New-JiraIssue +``` +This example illuetrates how to prepare multiple new stories and pipe them to be created all at once. + ## PARAMETERS ### -Project From d0ed7c551843c0f6e71b453c1b5a63fc0140321a Mon Sep 17 00:00:00 2001 From: Conor Tolan Date: Fri, 21 Sep 2018 23:17:42 +0100 Subject: [PATCH 18/29] Put verbose message back into begin block. Removed credential from param by pipeline. --- JiraPS/Public/New-JiraIssue.ps1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/JiraPS/Public/New-JiraIssue.ps1 b/JiraPS/Public/New-JiraIssue.ps1 index 1e04f668..0efe10b5 100644 --- a/JiraPS/Public/New-JiraIssue.ps1 +++ b/JiraPS/Public/New-JiraIssue.ps1 @@ -45,18 +45,17 @@ function New-JiraIssue { [PSCustomObject] $Fields, - [Parameter( ValueFromPipelineByPropertyName )] + [Parameter()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" } process { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" - $server = Get-JiraConfigServer -ErrorAction Stop -Debug:$false $createmeta = Get-JiraIssueCreateMetadata -Project $Project -IssueType $IssueType -Credential $Credential -ErrorAction Stop -Debug:$false From d73d9f791087b980a3f147068a7e62f6112874d7 Mon Sep 17 00:00:00 2001 From: Alex Suslin Date: Tue, 2 Oct 2018 00:23:01 +0300 Subject: [PATCH 19/29] Added Parameter -SkipNotification to Set-JiraIssue Command https://github.com/AtlassianPS/JiraPS/issues/315 --- JiraPS/Public/Set-JiraIssue.ps1 | 35 +++++++++++++++++------ Tests/Set-JiraIssue.Tests.ps1 | 5 ++++ docs/en-US/about_JiraPS_UpdatingIssues.md | 3 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 7f219d0d..10dcca27 100644 --- a/JiraPS/Public/Set-JiraIssue.ps1 +++ b/JiraPS/Public/Set-JiraIssue.ps1 @@ -56,7 +56,10 @@ function Set-JiraIssue { $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] - $PassThru + $PassThru, + + [Switch] + $SkipNotification ) begin { @@ -100,6 +103,13 @@ function Set-JiraIssue { } } } + + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("SkipNotification")){ + Write-Verbose "Users WON'T BE notified about the issues(s) updated" + } else { + Write-Verbose "Users WILL BE notified about the issues(s) updated" + } + } process { @@ -166,14 +176,20 @@ function Set-JiraIssue { } } + $SkipNotificationParams = @{} + if($SkipNotification){ + $SkipNotificationParams = @{notifyUsers = $false} + } + if ( @($issueProps.update.Keys).Count -gt 0 ) { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Updating issue fields" $parameter = @{ - URI = $issueObj.RestUrl - Method = "PUT" - Body = ConvertTo-Json -InputObject $issueProps -Depth 10 - Credential = $Credential + URI = $issueObj.RestUrl + Method = "PUT" + Body = ConvertTo-Json -InputObject $issueProps -Depth 10 + Credential = $Credential + GetParameter = $SkipNotificationParams } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" if ($PSCmdlet.ShouldProcess($issueObj.Key, "Updating Issue")) { @@ -187,10 +203,11 @@ function Set-JiraIssue { # you customize the "Edit Issue" screen. $parameter = @{ - URI = "{0}/assignee" -f $issueObj.RestUrl - Method = "PUT" - Body = ConvertTo-Json -InputObject $assigneeProps - Credential = $Credential + URI = "{0}/assignee" -f $issueObj.RestUrl + Method = "PUT" + Body = ConvertTo-Json -InputObject $assigneeProps + Credential = $Credential + GetParameter = $SkipNotificationParams } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" if ($PSCmdlet.ShouldProcess($issueObj.Key, "Updating Issue [Assignee] from JIRA")) { diff --git a/Tests/Set-JiraIssue.Tests.ps1 b/Tests/Set-JiraIssue.Tests.ps1 index ca594ea4..11969ed2 100644 --- a/Tests/Set-JiraIssue.Tests.ps1 +++ b/Tests/Set-JiraIssue.Tests.ps1 @@ -78,6 +78,11 @@ Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Put' -and $URI -like "$jiraServer/rest/api/2/issue/12345" -and $Body -like '*description*set*New description*' } } + It "Modifies the description of an issue without sending notifications if the -Description parameter is passed" { + { Set-JiraIssue -Issue TEST-001 -Description 'New description' -SkipNotification } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Put' -and $URI -like "$jiraServer/rest/api/2/issue/12345" -and $Body -like '*description*set*New description*' } + } + It "Modifies the assignee of an issue if -Assignee is passed" { { Set-JiraIssue -Issue TEST-001 -Assignee username } | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Put' -and $URI -like "$jiraServer/rest/api/2/issue/12345/assignee" -and $Body -like '*name*username*' } diff --git a/docs/en-US/about_JiraPS_UpdatingIssues.md b/docs/en-US/about_JiraPS_UpdatingIssues.md index f21c83ed..cd0aa33f 100644 --- a/docs/en-US/about_JiraPS_UpdatingIssues.md +++ b/docs/en-US/about_JiraPS_UpdatingIssues.md @@ -44,9 +44,10 @@ For more information on this parameter, see the [custom_fields](https://atlassia You can set labels on an issue using `Set-JiraIssue`'s `-Label` parameter. Using this function will overwrite any existing labels on the issue. +`-SkipNotification` parameter tells JIRA to not update users abouth the change. Default behaviour is always send notifications. ```powershell -Get-JiraIssue TEST-1 | Set-JiraIssue -Label 'Funny','Testing' +Get-JiraIssue TEST-1 | Set-JiraIssue -Label 'Funny','Testing' -SkipNotification ``` For better control over labels, use `Set-JiraIssueLabel`. From bb6609961308f4040c566a667a39a614efa1049c Mon Sep 17 00:00:00 2001 From: Alex Suslin Date: Tue, 2 Oct 2018 01:23:45 +0300 Subject: [PATCH 20/29] Updated Set-JiraIssue.md --- docs/en-US/commands/Set-JiraIssue.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/en-US/commands/Set-JiraIssue.md b/docs/en-US/commands/Set-JiraIssue.md index c3a13ee2..714f9aee 100644 --- a/docs/en-US/commands/Set-JiraIssue.md +++ b/docs/en-US/commands/Set-JiraIssue.md @@ -18,7 +18,7 @@ Modifies an existing issue in JIRA ```powershell Set-JiraIssue [-Issue] [[-Summary] ] [[-Description] ] [[-FixVersion] ] [[-Assignee] ] [[-Label] ] [[-Fields] ] [[-AddComment] ] - [[-Credential] ] [-PassThru] [-WhatIf] [-Confirm] [] + [[-Credential] ] [-SkipNotification] [-PassThru] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -31,10 +31,10 @@ This can include changing the issue's summary or description, or assigning the i ### EXAMPLE 1 ```powershell -Set-JiraIssue -Issue TEST-01 -Summary 'Modified issue summary' -Description 'This issue has been modified by PowerShell' +Set-JiraIssue -Issue TEST-01 -Summary 'Modified issue summary' -Description 'This issue has been modified by PowerShell' -SkipNotification ``` -This example changes the summary and description of the JIRA issue TEST-01. +This example changes the summary and description of the JIRA issue TEST-01 without updating users by email about the change. ### EXAMPLE 2 @@ -240,6 +240,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -SkipCredentials + +Whether send notification to users about issue change or not + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -PassThru Whether output should be provided after invoking this function. From 315953398cd363c625c1b351487e10b72d4964a0 Mon Sep 17 00:00:00 2001 From: Alex Suslin Date: Tue, 2 Oct 2018 01:57:03 +0300 Subject: [PATCH 21/29] fix typo in parameter name in documentation and remove Write-Verbose per @lipkau request --- JiraPS/Public/Set-JiraIssue.ps1 | 2 -- docs/en-US/commands/Set-JiraIssue.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 10dcca27..98152ede 100644 --- a/JiraPS/Public/Set-JiraIssue.ps1 +++ b/JiraPS/Public/Set-JiraIssue.ps1 @@ -106,8 +106,6 @@ function Set-JiraIssue { if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("SkipNotification")){ Write-Verbose "Users WON'T BE notified about the issues(s) updated" - } else { - Write-Verbose "Users WILL BE notified about the issues(s) updated" } } diff --git a/docs/en-US/commands/Set-JiraIssue.md b/docs/en-US/commands/Set-JiraIssue.md index 714f9aee..f2f04fc9 100644 --- a/docs/en-US/commands/Set-JiraIssue.md +++ b/docs/en-US/commands/Set-JiraIssue.md @@ -240,7 +240,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -SkipCredentials +### -SkipNotification Whether send notification to users about issue change or not From fa534345b5beaea5426e6cab20b2e8de43d89785 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 5 Dec 2018 22:52:10 +0100 Subject: [PATCH 22/29] Changed logic for verbose message --- JiraPS/Public/Set-JiraIssue.ps1 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 98152ede..29be3f35 100644 --- a/JiraPS/Public/Set-JiraIssue.ps1 +++ b/JiraPS/Public/Set-JiraIssue.ps1 @@ -103,11 +103,6 @@ function Set-JiraIssue { } } } - - if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("SkipNotification")){ - Write-Verbose "Users WON'T BE notified about the issues(s) updated" - } - } process { @@ -175,7 +170,8 @@ function Set-JiraIssue { } $SkipNotificationParams = @{} - if($SkipNotification){ + if ($SkipNotification) { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Skipping notification for watchers" $SkipNotificationParams = @{notifyUsers = $false} } From 3d48685a091c6f81a06acc38d0c74bf1fc6fb568 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 5 Dec 2018 23:49:09 +0100 Subject: [PATCH 23/29] Fix for binary file --- Tools/PackageManagement_x64.msi | Bin 720896 -> 720167 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Tools/PackageManagement_x64.msi b/Tools/PackageManagement_x64.msi index 6f97aae8dc8b0cc10606432983784fc736a74a5f..b78a58e460dc0a92ae7f6e41c14827e8902f7d3f 100644 GIT binary patch delta 7805 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 Q8xhMksA-!HCG`gX7iAsNlK=n! delta 8999 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 Date: Thu, 6 Dec 2018 00:14:18 +0100 Subject: [PATCH 24/29] Added group membership when querying the current user --- JiraPS/Public/Get-JiraUser.ps1 | 2 +- Tests/Functions/Get-JiraUser.Unit.Tests.ps1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Get-JiraUser.ps1 b/JiraPS/Public/Get-JiraUser.ps1 index 807d7587..640517ce 100644 --- a/JiraPS/Public/Get-JiraUser.ps1 +++ b/JiraPS/Public/Get-JiraUser.ps1 @@ -72,7 +72,7 @@ function Get-JiraUser { Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" $result = Invoke-JiraMethod @parameter - Write-Output (ConvertTo-JiraUser -InputObject $result) + Get-JiraUser -UserName $result.Name } "ByInputObject" { $UserName = $InputObject.Name diff --git a/Tests/Functions/Get-JiraUser.Unit.Tests.ps1 b/Tests/Functions/Get-JiraUser.Unit.Tests.ps1 index 0c69089d..cd09868c 100644 --- a/Tests/Functions/Get-JiraUser.Unit.Tests.ps1 +++ b/Tests/Functions/Get-JiraUser.Unit.Tests.ps1 @@ -130,6 +130,7 @@ Describe "Get-JiraUser" -Tag 'Unit' { $getResult | Should Not BeNullOrEmpty Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly 1 -Scope It -ParameterFilter {$URI -like "$jiraServer/rest/api/*/myself"} + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly 1 -Scope It -ParameterFilter {$URI -like "$jiraServer/rest/api/*/user?username=$testUsername&expand=groups"} } It "Gets information about a provided Jira user" { From 9ecc07a5e40e97e65934b9d29daab1ef7c6cceae Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 6 Dec 2018 09:41:13 +0100 Subject: [PATCH 25/29] Added documentation for authenticating with PAT closes #313 --- docs/en-US/about_JiraPS_Authentication.md | 63 +++++++++++++++++------ 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/docs/en-US/about_JiraPS_Authentication.md b/docs/en-US/about_JiraPS_Authentication.md index 11781b97..57ff980e 100644 --- a/docs/en-US/about_JiraPS_Authentication.md +++ b/docs/en-US/about_JiraPS_Authentication.md @@ -11,35 +11,65 @@ permalink: /docs/JiraPS/about/authentication.html # SHORT DESCRIPTION -In order to authenticate with the Jira server, the user can provide the credentials with each command or create a session. +In order to authenticate with the Jira server, the user can provide the +credentials with each command or create a session. # LONG DESCRIPTION At present, there are two main methods of authenticating to Jira: * HTTP basic authentication -* session-based authentication, which uses HTTP basic authentication once and preserves a session cookie. +* session-based authentication, +which uses HTTP basic authentication once and preserves a session cookie. -> Be sure to set JIRA up to use HTTPS with a valid SSL certificate if you are concerned about security! +> Be sure to set JIRA up to use HTTPS with a valid SSL certificate if you are +> concerned about security! ## HTTP Basic -Each JiraPS function that queries a Jira instance provides a `-Credential` parameter. Simply pass your Jira credentials to this parameter. +Each JiraPS function that queries a Jira instance provides +a `-Credential` parameter. +Simply pass your Jira credentials to this parameter. ```powershell $cred = Get-Credential 'powershell' Get-JiraIssue TEST-01 -Credential $cred ``` -> HTTP basic authentication is not a secure form of authentication. It uses a Base64-encoded String of the format "username:password", and passes this string in clear text to Jira. Because decrypting this string and obtaining the username and password is trivial, the use of HTTPS is critical in any system that needs to remain secure. +> HTTP basic authentication is not a secure form of authentication. +> It uses a Base64-encoded String of the format "username:password" +> and passes this string in clear text to Jira. Because decrypting this +> string and obtaining the username and password is trivial, +> the use of HTTPS is critical in any system that needs to remain secure. + +## API Token + +API tokens (also called Private Access Token (PAT)) are tokens generated +by the user. This token is necessary when the user has a two-step verification +activated for his account. + +An API token can be used for authenticating JiraPS with the server +in the same way as described in [HTTP Basic](#http-basic). +The only difference is, that instead of providing the password for the account, +the API token must be used. + +> As of December 1st 2018, Atlassian requires API authentication +> with **Cloud Servers** to **always** use API Tokens. +> More information in the [Deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth/). + +_More information on the API tokens and how to create one can be found at:_ +__ ## Sessions -Jira sessions still require HTTP Basic Authentication once to create the connection. -But in this case a persistent session is saved as a `WebRequestSession`. This is Powershell's way of reusing the data provided with the first call. +Jira sessions still require [HTTP Basic](#http-basic) or [API Token](#api-token) +Authentication once to create the connection. +But in this case a persistent session is saved as a `WebRequestSession`. +This is Powershell's way of reusing the data provided with the first call. -> Previously Jira allowed for the authentication to use a session token. This token did not contain the username and password. -> But unfortunately, this API can no longer be used in combination with this module. +> Previously Jira allowed for the authentication to use a session token. +> This token did not contain the username and password. +> Unfortunately, this API can no longer be used in combination with this module. To create a Jira session, you can use the New-JiraSession function: @@ -48,17 +78,20 @@ $cred = Get-Credential 'powershell' New-JiraSession -Credential $cred ``` -Once you've created this session, you're done! You don't need to specify it when running other commands - JiraPS will manage this session internally. +Once you've created this session, you're done! +You don't need to specify it when running other commands - JiraPS will +manage this session internally. The session is stored in the module's runtime. -This means that it will not be available in a new Powershell session or if the module is reloaded. +This means that it will not be available in a new Powershell session +or if the module is reloaded. -## What About OAuth? +## What About OAuth -Jira does support use of OAuth, but JiraPS does not yet. +Jira does support use of OAuth, but JiraPS does not - yet. This is a to-do item. # SEE ALSO -- [Wikipedia's "Basic Access Authentication"](https://en.wikipedia.org/wiki/Basic_access_authentication) -- [Implement OAuth for JiraPS](https://github.com/AtlassianPS/JiraPS/issues/101) +* [Wikipedia's "Basic Access Authentication"](https://en.wikipedia.org/wiki/Basic_access_authentication) +* [Implement OAuth for JiraPS](https://github.com/AtlassianPS/JiraPS/issues/101) From 2543b4ecf4c2c36e16f4f7c95f5e6c1d669500cc Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 6 Dec 2018 13:55:39 +0100 Subject: [PATCH 26/29] Removed error for issues without attachments --- JiraPS/Public/Get-JiraIssueAttachment.ps1 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssueAttachment.ps1 b/JiraPS/Public/Get-JiraIssueAttachment.ps1 index cf833b16..8efae370 100644 --- a/JiraPS/Public/Get-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Get-JiraIssueAttachment.ps1 @@ -59,14 +59,6 @@ function Get-JiraIssueAttachment { ConvertTo-JiraAttachment -InputObject $attachments } - else { - $errorMessage = @{ - Category = "ObjectNotFound" - CategoryActivity = "Searching for resource" - Message = "This issue does not have any attachments" - } - Write-Error @errorMessage - } } end { From 5015419161fff86c3963b7794f7806b52f259a8f Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 6 Dec 2018 13:55:55 +0100 Subject: [PATCH 27/29] Added function for persisting attachment to disk --- JiraPS/Public/Get-JiraIssueAttachmentFile.ps1 | 68 ++++++++ ...Get-JiraIssueAttachmentFile.Unit.Tests.ps1 | 154 ++++++++++++++++++ .../en-US/commands/Get-JiraIssueAttachment.md | 2 + .../commands/Get-JiraIssueAttachmentFile.md | 138 ++++++++++++++++ 4 files changed, 362 insertions(+) create mode 100644 JiraPS/Public/Get-JiraIssueAttachmentFile.ps1 create mode 100644 Tests/Functions/Get-JiraIssueAttachmentFile.Unit.Tests.ps1 create mode 100644 docs/en-US/commands/Get-JiraIssueAttachmentFile.md diff --git a/JiraPS/Public/Get-JiraIssueAttachmentFile.ps1 b/JiraPS/Public/Get-JiraIssueAttachmentFile.ps1 new file mode 100644 index 00000000..4021a752 --- /dev/null +++ b/JiraPS/Public/Get-JiraIssueAttachmentFile.ps1 @@ -0,0 +1,68 @@ +function Get-JiraIssueAttachmentFile { + # .ExternalHelp ..\JiraPS-help.xml + [CmdletBinding()] + [OutputType([Bool])] + param ( + [Parameter( Mandatory, ValueFromPipeline )] + [PSTypeName('JiraPS.Attachment')] + $Attachment, + + [ValidateScript( + { + if (-not (Test-Path $_)) { + $errorItem = [System.Management.Automation.ErrorRecord]::new( + ([System.ArgumentException]"Path not found"), + 'ParameterValue.FileNotFound', + [System.Management.Automation.ErrorCategory]::ObjectNotFound, + $_ + ) + $errorItem.ErrorDetails = "Invalid path '$_'." + $PSCmdlet.ThrowTerminatingError($errorItem) + } + else { + return $true + } + } + )] + [String] + $Path, + + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty + ) + + begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + } + + process { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + foreach ($_Attachment in $Attachment) { + if ($Path) { + $filename = Join-Path $Path $_Attachment.Filename + } + else { + $filename = $_Attachment.Filename + } + + $iwParameters = @{ + Uri = $_Attachment.Content + Method = 'Get' + Headers = @{"Accept" = $_Attachment.MediaType} + OutFile = $filename + Credential = $Credential + } + + $result = Invoke-JiraMethod @iwParameters + (-not $result) + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended" + } +} diff --git a/Tests/Functions/Get-JiraIssueAttachmentFile.Unit.Tests.ps1 b/Tests/Functions/Get-JiraIssueAttachmentFile.Unit.Tests.ps1 new file mode 100644 index 00000000..eeb9863f --- /dev/null +++ b/Tests/Functions/Get-JiraIssueAttachmentFile.Unit.Tests.ps1 @@ -0,0 +1,154 @@ +#requires -modules BuildHelpers +#requires -modules @{ ModuleName = "Pester"; ModuleVersion = "4.4.0" } + +Describe "Get-JiraIssueAttachmentFile" -Tag 'Unit' { + + BeforeAll { + Remove-Item -Path Env:\BH* + $projectRoot = (Resolve-Path "$PSScriptRoot/../..").Path + if ($projectRoot -like "*Release") { + $projectRoot = (Resolve-Path "$projectRoot/..").Path + } + + Import-Module BuildHelpers + Set-BuildEnvironment -BuildOutput '$ProjectPath/Release' -Path $projectRoot -ErrorAction SilentlyContinue + + $env:BHManifestToTest = $env:BHPSModuleManifest + $script:isBuild = $PSScriptRoot -like "$env:BHBuildOutput*" + if ($script:isBuild) { + $Pattern = [regex]::Escape($env:BHProjectPath) + + $env:BHBuildModuleManifest = $env:BHPSModuleManifest -replace $Pattern, $env:BHBuildOutput + $env:BHManifestToTest = $env:BHBuildModuleManifest + } + + Import-Module "$env:BHProjectPath/Tools/BuildTools.psm1" + + Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue + Import-Module $env:BHManifestToTest + } + AfterAll { + Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue + Remove-Module BuildHelpers -ErrorAction SilentlyContinue + Remove-Item -Path Env:\BH* + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/../Shared.ps1" + + $jiraServer = 'http://jiraserver.example.com' + $issueID = 41701 + $issueKey = 'IT-3676' + + $attachments = @" +[ + { + "self": "$jiraServer/rest/api/2/attachment/10013", + "id": "10013", + "filename": "foo.pdf", + "author": { + "self": "$jiraServer/rest/api/2/user?username=admin", + "name": "admin", + "key": "admin", + "accountId": "000000:000000-0000-0000-0000-ab899c878d00", + "emailAddress": "admin@example.com", + "avatarUrls": { }, + "displayName": "Admin", + "active": true, + "timeZone": "Europe/Berlin" + }, + "created": "2017-10-16T10:06:29.399+0200", + "size": 60444, + "mimeType": "application/pdf", + "content": "$jiraServer/secure/attachment/10013/foo.pdf" + }, + { + "self": "$jiraServer/rest/api/2/attachment/10010", + "id": "10010", + "filename": "bar.pdf", + "author": { + "self": "$jiraServer/rest/api/2/user?username=admin", + "name": "admin", + "key": "admin", + "accountId": "000000:000000-0000-0000-0000-ab899c878d00", + "emailAddress": "admin@example.com", + "avatarUrls": { }, + "displayName": "Admin", + "active": true, + "timeZone": "Europe/Berlin" + }, + "created": "2017-10-16T09:06:48.070+0200", + "size": 438098, + "mimeType": "'application/pdf'", + "content": "$jiraServer/secure/attachment/10010/bar.pdf" + } +] +"@ + + Mock Get-JiraIssueAttachment -ModuleName JiraPS { + $object = ConvertFrom-Json -InputObject $attachments + $object[0].PSObject.TypeNames.Insert(0, 'JiraPS.Attachment') + $object[1].PSObject.TypeNames.Insert(0, 'JiraPS.Attachment') + $object + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Method -eq 'Get' -and + $URI -like "$jiraServer/secure/attachment/*" + } { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'OutFile' + } + + # Generic catch-all. This will throw an exception if we forgot to mock something. + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + + ############# + # Tests + ############# + + It 'only accepts JiraPS.Attachment as input' { + { Get-JiraIssueAttachmentFile -Attachment (Get-Date) } | Should Throw + { Get-JiraIssueAttachmentFile -Attachment (Get-ChildItem) } | Should Throw + { Get-JiraIssueAttachmentFile -Attachment @('foo', 'bar') } | Should Throw + { Get-JiraIssueAttachmentFile -Attachment (Get-JiraIssueAttachment -Issue "Foo") } | Should Not Throw + } + + It 'takes the issue input over the pipeline' { + { Get-JiraIssueAttachment -Issue "Foo" | Get-JiraIssueAttachmentFile } | Should Not Throw + } + + It 'uses Invoke-JiraMethod for saving to disk' { + $script:ShowMockData = $true + Get-JiraIssueAttachment -Issue "Foo" | Get-JiraIssueAttachmentFile + Get-JiraIssueAttachment -Issue "Foo" | Get-JiraIssueAttachmentFile -Path "../" + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = "JiraPS" + ParameterFilter = { + $OutFile -in @("foo.pdf", "bar.pdf") + } + Exactly = $true + Times = 2 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = "JiraPS" + ParameterFilter = { + $OutFile -like "..*.pdf" + } + Exactly = $true + Times = 2 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + } +} diff --git a/docs/en-US/commands/Get-JiraIssueAttachment.md b/docs/en-US/commands/Get-JiraIssueAttachment.md index 93b5d630..f0ae1905 100644 --- a/docs/en-US/commands/Get-JiraIssueAttachment.md +++ b/docs/en-US/commands/Get-JiraIssueAttachment.md @@ -126,6 +126,8 @@ If neither are supplied, this function will run with anonymous access to JIRA. ## RELATED LINKS +[Get-JiraAttachmentFile](../Get-JiraAttachmentFile/) + [Add-JiraIssueAttachment](../Add-JiraIssueAttachment/) [Get-JiraIssue](../Get-JiraIssue/) diff --git a/docs/en-US/commands/Get-JiraIssueAttachmentFile.md b/docs/en-US/commands/Get-JiraIssueAttachmentFile.md new file mode 100644 index 00000000..1be58aba --- /dev/null +++ b/docs/en-US/commands/Get-JiraIssueAttachmentFile.md @@ -0,0 +1,138 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/Get-JiraIssueAttachmentFile/ +locale: en-US +schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Get-JiraIssueAttachmentFile/ +--- +# Get-JiraIssueAttachmentFile + +## SYNOPSIS + +Save an attachment to disk. + +## SYNTAX + +```powershell +Get-JiraIssueAttachmentFile [-Attachment] [[-Path] ]] + [[-Credential] ] [] +``` + +## DESCRIPTION + +This function downloads an attachment of an issue to the local disk. + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +Get-JiraIssueAttachmentFile (Get-JiraIssueAttachment -Issue TEST-001) +``` + +This example downloads all attachments from issue TEST-001 to the current +working directory. + +### EXAMPLE 2 + +```powershell +Get-JiraIssue TEST-002 | Get-JiraIssueAttachment | Get-JiraIssueAttachmentFile +``` + +This example illustrates use of the pipeline to download all attachments from +issue TEST-002. + +### EXAMPLE 3 + +```powershell +Get-JiraIssue TEST-002 | + Get-JiraIssueAttachment -FileName "*.png" | + Get-JiraIssueAttachmentFile -Path "c:\temp +``` + +Download all attachments of issue TEST-002 where the filename ends in `.png` +to a specific location. + +## PARAMETERS + +### -Attachment + +Attachment which will be downloaded. + +```yaml +Type: JiraPS.Attachment +Parameter Sets: (All) +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -Path + +Path in which to store to attachment. + +The name of the file will be appended to the Path provided. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Credential + +Credentials to use to connect to JIRA. +If not specified, this function will use anonymous access. + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: 3 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### [JiraPS.Attachment] + +## OUTPUTS + +### [Bool] + +## 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. + +## RELATED LINKS + +[Get-JiraAttachment](../Get-JiraAttachmentFile/) + +[Add-JiraIssueAttachmentFile](../Add-JiraIssueAttachmentFile/) + +[Get-JiraIssue](../Get-JiraIssue/) + +[Remove-JiraIssueAttachmentFile](../Remove-JiraIssueAttachmentFile/) From 1f5f641a00de17cbe443ca7b826f59cf387e7f22 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 12 Dec 2018 14:53:52 +0100 Subject: [PATCH 28/29] Fixed the DateTime representation of DateStarted closes #324 --- JiraPS/Public/Add-JiraIssueWorklog.ps1 | 5 +++++ Tests/Functions/Add-JiraIssueWorklog.Unit.Tests.ps1 | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Add-JiraIssueWorklog.ps1 b/JiraPS/Public/Add-JiraIssueWorklog.ps1 index edb067a2..60fcc59a 100644 --- a/JiraPS/Public/Add-JiraIssueWorklog.ps1 +++ b/JiraPS/Public/Add-JiraIssueWorklog.ps1 @@ -73,6 +73,11 @@ function Add-JiraIssueWorklog { Write-Error @errorMessage } + # Harmonize DateStarted: + # `Get-Date -Date "01.01.2000"` does not return the local timezone + # which is required by the API + $DateStarted = [DateTime]::new($DateStarted.Ticks, 'Local') + $requestBody = @{ 'comment' = $Comment # We need to fix the date with a RegEx replace because the API does not like: diff --git a/Tests/Functions/Add-JiraIssueWorklog.Unit.Tests.ps1 b/Tests/Functions/Add-JiraIssueWorklog.Unit.Tests.ps1 index 9f85e07f..4e6ae499 100644 --- a/Tests/Functions/Add-JiraIssueWorklog.Unit.Tests.ps1 +++ b/Tests/Functions/Add-JiraIssueWorklog.Unit.Tests.ps1 @@ -103,7 +103,7 @@ Describe "Add-JiraIssueWorklog" -Tag 'Unit' { } Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'POST' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/worklog"} { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'Body' ConvertFrom-Json $restResponse } @@ -136,5 +136,15 @@ Describe "Add-JiraIssueWorklog" -Tag 'Unit' { Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 2 -Scope It Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } + + It "formats DateStarted independetly of the input" { + Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent "00:10:00" -DateStarted "2018-01-01" + Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent "00:10:00" -DateStarted (Get-Date) + Add-JiraIssueWorklog -Comment 'This is a test worklog entry from Pester.' -Issue $issueKey -TimeSpent "00:10:00" -DateStarted (Get-Date -Date "01.01.2000") + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { + $Body -match '\"started\":\s*"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}[\+\-]\d{4}"' + } -Exactly -Times 3 -Scope It + } } } From db256de33b830c50e2f2599247adc99855aa89bb Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 12 Dec 2018 23:01:21 +0100 Subject: [PATCH 29/29] Bumped version to v2.9 --- CHANGELOG.md | 24 ++++++++++++++++++++++++ JiraPS/JiraPS.psd1 | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c4d3b07..b51ccb21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Change Log +## [2.9] - 2018-12-12 + +### Added + +- Parameter for selecting what fields to return the the issue's payload (#300, [@tuxgoose]) +- Added pipeline support to `New-JiraIssue` (#312, [@ctolan]) +- Added parameter to avoid notifying user when running `Set-JiraIssue` (#315, [@alexsuslin]) +- Improved documentation to demonstrate how to authenticate with 2FA (#313, [@lipkau]) +- Added function to download attachments from issue: `Get-JiraIssueAttachmentFile` (#323, [@lipkau]) + +### Changed + +- Fixed the way a user is resolved in `Remove-JiraGroupMember` (#301, [@lipkau]) +- Improved the resolving of server responses with an error (#303, [@lipkau]) +- Fixed payload of `New-JiraFilter` (#304, [@lipkau]) +- Fixed paging when server responds with only 1 result (#307, [@lipkau]) +- Fixed `Set-JiraIssue` to allow to unassigned an issue (#309, [@lipkau]) +- Changed CI/CD pipeline from AppVeyor to Azure DevOps (#317, [@lipkau]) +- Fixed missing properties on `Get-JiraUser` (#321, [@lipkau]) +- Fixed `-DateStarted` on `Add-JiraIssueWorklog` (#324, [@lipkau]) + + ## [2.8] - 2018-06-28 More detailed description about the changes can be found on [Our Website](https://atlassianps.org/article/announcement/JiraPS-v2.8.html). @@ -279,6 +301,7 @@ which is in turn inspired by the [Vagrant](https://github.com/mitchellh/vagrant/ [@beaudryj]: https://github.com/beaudryj [@brianbunke]: https://github.com/brianbunke [@Clijsters]: https://github.com/Clijsters + [@ctolan]: https://github.com/ctolan [@colhal]: https://github.com/colhal [@Dejulia489]: https://github.com/Dejulia489 [@ebekker]: https://github.com/ebekker @@ -290,4 +313,5 @@ which is in turn inspired by the [Vagrant](https://github.com/mitchellh/vagrant/ [@lukhase]: https://github.com/lukhase [@padgers]: https://github.com/padgers [@ThePSAdmin]: https://github.com/ThePSAdmin + [@tuxgoose]: https://github.com/tuxgoose [@WindowsAdmin92]: https://github.com/WindowsAdmin92 diff --git a/JiraPS/JiraPS.psd1 b/JiraPS/JiraPS.psd1 index 6dba9ffe..75c2ed6f 100644 --- a/JiraPS/JiraPS.psd1 +++ b/JiraPS/JiraPS.psd1 @@ -4,7 +4,7 @@ RootModule = 'JiraPS.psm1' # Version number of this module. - ModuleVersion = '2.8' + ModuleVersion = '2.9' # Supported PSEditions # CompatiblePSEditions = @()