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 = @() 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/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 517b83fb..ae208d0c 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -65,6 +65,11 @@ function Get-JiraIssue { [Object] $Filter, + [Parameter()] + [ValidateNotNullOrEmpty()] + [String[]] + $Fields = "*all", + [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] [UInt32] @@ -91,8 +96,10 @@ function Get-JiraIssue { $server = Get-JiraConfigServer -ErrorAction Stop - $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" $searchURi = "$server/rest/api/latest/search" + $resourceURi = "$server/rest/api/latest/issue/{0}" + + [String]$Fields = $Fields -join "," } process { @@ -105,11 +112,18 @@ function Get-JiraIssue { 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" - Credential = $Credential + URI = $resourceURi -f $_key + Method = "GET" + GetParameter = $getParameter + Credential = $Credential } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" $result = Invoke-JiraMethod @parameter @@ -122,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' { @@ -134,11 +148,15 @@ function Get-JiraIssue { 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.$_ @@ -158,14 +176,14 @@ function Get-JiraIssue { Invoke-JiraMethod @parameter } 'ByFilter' { - $filterObj = Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop + $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.SearchUrl + URI = $filterObj Method = "GET" GetParameter = @{ validateQuery = $true @@ -175,6 +193,10 @@ function Get-JiraIssue { OutputType = "JiraIssue" Paging = $true Credential = $Credential + + } + if ($Fields) { + $parameter["GetParameter"]["fields"] = $Fields } # Paging ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { 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 { 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/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/JiraPS/Public/New-JiraIssue.ps1 b/JiraPS/Public/New-JiraIssue.ps1 index e2a4ebc7..53751b6d 100644 --- a/JiraPS/Public/New-JiraIssue.ps1 +++ b/JiraPS/Public/New-JiraIssue.ps1 @@ -2,39 +2,46 @@ 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, @@ -46,15 +53,15 @@ function New-JiraIssue { begin { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + } + process { $server = Get-JiraConfigServer -ErrorAction Stop -Debug:$false $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 +168,9 @@ function New-JiraIssue { 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/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 7f7fd1a9..2dfb465e 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 { @@ -175,14 +178,21 @@ function Set-JiraIssue { } } + $SkipNotificationParams = @{} + if ($SkipNotification) { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Skipping notification for watchers" + $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")) { @@ -196,10 +206,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/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 + } } } diff --git a/Tests/Functions/Get-JiraIssue.Unit.Tests.ps1 b/Tests/Functions/Get-JiraIssue.Unit.Tests.ps1 index b8a145b0..e4342e20 100644 --- a/Tests/Functions/Get-JiraIssue.Unit.Tests.ps1 +++ b/Tests/Functions/Get-JiraIssue.Unit.Tests.ps1 @@ -1,7 +1,7 @@ #requires -modules BuildHelpers #requires -modules @{ ModuleName = "Pester"; ModuleVersion = "4.4.0" } -Describe "Get-JiraIssue" -Tag 'Unit' { +Describe "Get-JiraGroupMember" -Tag 'Unit' { BeforeAll { Remove-Item -Path Env:\BH* @@ -59,31 +59,54 @@ Describe "Get-JiraIssue" -Tag 'Unit' { '@ #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 @@ -94,6 +117,7 @@ Describe "Get-JiraIssue" -Tag 'Unit' { defParam $command 'InputObject' defParam $command 'Query' defParam $command 'Filter' + defParam $command 'Fields' defParam $command 'StartIndex' defParam $command 'MaxResults' defParam $command 'PageSize' @@ -103,7 +127,7 @@ Describe "Get-JiraIssue" -Tag 'Unit' { 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' @@ -120,7 +144,7 @@ Describe "Get-JiraIssue" -Tag 'Unit' { } 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' @@ -138,7 +162,7 @@ Describe "Get-JiraIssue" -Tag 'Unit' { } 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' @@ -158,7 +182,7 @@ Describe "Get-JiraIssue" -Tag 'Unit' { } 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' @@ -175,11 +199,78 @@ Describe "Get-JiraIssue" -Tag 'Unit' { } 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' @@ -203,7 +294,7 @@ Describe "Get-JiraIssue" -Tag 'Unit' { $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' 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/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" { diff --git a/Tests/Functions/New-JiraIssue.Unit.Tests.ps1 b/Tests/Functions/New-JiraIssue.Unit.Tests.ps1 index cef3aa84..8ccb039f 100644 --- a/Tests/Functions/New-JiraIssue.Unit.Tests.ps1 +++ b/Tests/Functions/New-JiraIssue.Unit.Tests.ps1 @@ -111,6 +111,8 @@ Describe "New-JiraIssue" -Tag 'Unit' { 'Description' = 'Test description'; } + $pipelineParams = New-Object -TypeName PSCustomObject -Property $newParams + Context "Sanity checking" { $command = Get-Command -Name New-JiraIssue @@ -133,6 +135,13 @@ Describe "New-JiraIssue" -Tag 'Unit' { # 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" { diff --git a/Tests/Functions/Set-JiraIssue.Unit.Tests.ps1 b/Tests/Functions/Set-JiraIssue.Unit.Tests.ps1 index 249faafd..1dd2cd00 100644 --- a/Tests/Functions/Set-JiraIssue.Unit.Tests.ps1 +++ b/Tests/Functions/Set-JiraIssue.Unit.Tests.ps1 @@ -109,6 +109,11 @@ Describe "Set-JiraIssue" -Tag 'Unit' { 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_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) 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`. diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index 5a01c7c9..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] [-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 [-StartIndex ] [-MaxResults ] [[PageSize] ] - [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] +Get-JiraIssue -Query [-Fields ] [-StartIndex ] +[-MaxResults ] [[PageSize] ] [-IncludeTotalCount] [-Skip ] + [-First ] [-Credential ] [] ``` ### ByFilter ```powershell -Get-JiraIssue -Filter [-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 @@ -173,6 +187,31 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Fields + +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[] +Parameter Sets: ByFilter +Aliases: + +Required: False +Position: Named +Default value: "*all" +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. 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/) 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 diff --git a/docs/en-US/commands/Set-JiraIssue.md b/docs/en-US/commands/Set-JiraIssue.md index 79f06105..0fbf07de 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 @@ -248,6 +248,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -SkipNotification + +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.