From 7c508f9ba58197f758d567ff6f3f28866fa1b785 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 14 May 2018 10:02:02 +0200 Subject: [PATCH 01/83] Fixed deployment of hompage update --- JiraPS.build.ps1 | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/JiraPS.build.ps1 b/JiraPS.build.ps1 index fbc44ac3..43ddafba 100644 --- a/JiraPS.build.ps1 +++ b/JiraPS.build.ps1 @@ -51,6 +51,10 @@ task InstallDependencies { # Synopsis: Ensure the build environment is all ready to go task Init { Set-BuildEnvironment -BuildOutput '$ProjectPath/Release' -ErrorAction SilentlyContinue + # BuildHelpers does not write the project name in the correct caps + if ($env:APPVEYOR_PROJECT_NAME) { + $env:BHProjectName = $env:APPVEYOR_PROJECT_NAME + } Add-ToModulePath -Path $env:BHBuildOutput }, GetNextVersion @@ -257,23 +261,22 @@ task TagReplository GetNextVersion, { task UpdateHomepage { try { Write-Build Gray "git close .../AtlassianPS.github.io --recursive" - cmd /c "git clone https://github.com/AtlassianPS/AtlassianPS.github.io --recursive 2>&1" + $null = cmd /c "git clone https://github.com/AtlassianPS/AtlassianPS.github.io --recursive 2>&1" Push-Location "AtlassianPS.github.io/" Write-Build Gray "git submodule foreach git pull origin master" - cmd /c "git submodule foreach git pull origin master 2>&1" + $null = cmd /c "git submodule foreach git pull origin master 2>&1" Write-Build Gray "git status -s" $status = cmd /c "git status -s 2>&1" - Write-Build Gray $status if ($status -contains " M modules/$env:BHProjectName") { Write-Build Gray "git add modules/$env:BHProjectName" - cmd /c "git add modules/$env:BHProjectName 2>&1" + $null = cmd /c "git add modules/$env:BHProjectName 2>&1" - Write-Build Gray "git commit -m `"Update module $PROJECT_NAME`"" - cmd /c "git commit -m `"Update module $PROJECT_NAME`" 2>&1" + Write-Build Gray "git commit -m `"Update module $env:BHProjectName`"" + cmd /c "git commit -m `"Update module $env:BHProjectName`" 2>&1" Write-Build Gray "git push" cmd /c "git push 2>&1" @@ -281,7 +284,7 @@ task UpdateHomepage { Pop-Location } - catch {} + catch { Write-Warning "Failed to deploy to homepage"} } #endregion Publish From b27868d567ca80292ff5d09e7b61f1ef09cde91e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 12:43:25 +0200 Subject: [PATCH 02/83] Added `-Favorite` parameter to find all favorite filters --- JiraPS/Public/Get-JiraFilter.ps1 | 16 ++++ Tests/Get-JiraFilter.Tests.ps1 | 107 +++++++++++++++++++++----- docs/en-US/commands/Get-JiraFilter.md | 39 +++++++++- 3 files changed, 139 insertions(+), 23 deletions(-) diff --git a/JiraPS/Public/Get-JiraFilter.ps1 b/JiraPS/Public/Get-JiraFilter.ps1 index 4ca4d6b8..e05379a6 100644 --- a/JiraPS/Public/Get-JiraFilter.ps1 +++ b/JiraPS/Public/Get-JiraFilter.ps1 @@ -37,6 +37,11 @@ [Object[]] $InputObject, + [Parameter( Mandatory, ParameterSetName = 'MyFavorite' )] + [Alias('Favourite')] + [Switch] + $Favorite, + [PSCredential] $Credential ) @@ -86,6 +91,17 @@ Write-Output (Get-JiraFilter -Id $thisId -Credential $Credential) } } + "MyFavorite" { + $parameter = @{ + URI = $resourceURi -f "favourite" + Method = "GET" + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraFilter -InputObject $result) + } } } diff --git a/Tests/Get-JiraFilter.Tests.ps1 b/Tests/Get-JiraFilter.Tests.ps1 index f3fd631e..5b759768 100644 --- a/Tests/Get-JiraFilter.Tests.ps1 +++ b/Tests/Get-JiraFilter.Tests.ps1 @@ -1,34 +1,37 @@ Describe 'Get-JiraFilter' { - - Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + BeforeAll { + Remove-Module JiraPS + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } InModuleScope JiraPS { . "$PSScriptRoot/Shared.ps1" + #region Definitions $jiraServer = "https://jira.example.com" - $response = @' + $responseFilter = @" { - "self": "https://jira.atlassian.com/rest/api/latest/filter/12844", + "self": "$jiraServer/rest/api/latest/filter/12844", "id": "12844", "name": "All JIRA Bugs", "owner": { - "self": "https://jira.atlassian.com/rest/api/2/user?username=scott@atlassian.com", + "self": "$jiraServer/rest/api/2/user?username=scott@atlassian.com", "key": "scott@atlassian.com", "name": "scott@atlassian.com", "avatarUrls": { - "16x16": "https://jira.atlassian.com/secure/useravatar?size=xsmall&avatarId=10612", - "24x24": "https://jira.atlassian.com/secure/useravatar?size=small&avatarId=10612", - "32x32": "https://jira.atlassian.com/secure/useravatar?size=medium&avatarId=10612", - "48x48": "https://jira.atlassian.com/secure/useravatar?avatarId=10612" + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10612", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10612", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10612", + "48x48": "$jiraServer/secure/useravatar?avatarId=10612" }, "displayName": "Scott Farquhar [Atlassian]", "active": true }, "jql": "project = 10240 AND issuetype = 1 ORDER BY key DESC", - "viewUrl": "https://jira.atlassian.com/secure/IssueNavigator.jspa?mode=hide&requestId=12844", - "searchUrl": "https://jira.atlassian.com/rest/api/latest/search?jql=project+%3D+10240+AND+issuetype+%3D+1+ORDER+BY+key+DESC", + "viewUrl": "$jiraServer/secure/IssueNavigator.jspa?mode=hide&requestId=12844", + "searchUrl": "$jiraServer/rest/api/latest/search?jql=project+%3D+10240+AND+issuetype+%3D+1+ORDER+BY+key+DESC", "favourite": false, "sharePermissions": [ { @@ -51,36 +54,82 @@ "end-index": 0 } } -'@ +"@ + + $responseFilterCollection = @" +[ + { + "self": "$jiraServer/rest/api/latest/filter/13844", + "id": "13844", + "name": "Filter 1", + "jql": "project = 10240 AND issuetype = 1 ORDER BY key DESC", + "favourite": true + }, + { + "self": "$jiraServer/rest/api/latest/filter/14844", + "id": "14844", + "name": "Filter 2", + "jql": "project = 10240 AND issuetype = 1 ORDER BY key DESC", + "favourite": true + }, + { + "self": "$jiraServer/rest/api/latest/filter/15844", + "id": "15844", + "name": "Filter 3", + "jql": "project = 10240 AND issuetype = 1 ORDER BY key DESC", + "favourite": true + } +] +"@ + #endregion Definitions - Mock Get-JiraConfigServer { + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { $jiraServer } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/filter/12345"} { + Mock ConvertTo-JiraFilter -ModuleName JiraPS { + foreach ($i in $InputObject) { + $i.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $i + } + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/filter/12345"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + ConvertFrom-Json $responseFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/filter/67890"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json $response + ConvertFrom-Json $responseFilter } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/filter/67890"} { + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/filter/favourite"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json $response + ConvertFrom-Json $responseFilterCollection } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/filter/*"} { + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/filter/*"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json $response + ConvertFrom-Json $responseFilter } Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } + #endregion Mocks Context "Sanity checking" { $command = Get-Command -Name Get-JiraFilter defParam $command 'Id' defParam $command 'InputObject' + defParam $command 'Favorite' defParam $command 'Credential' + + defAlias $command 'Favourite' 'Favorite' } Context "Behavior testing" { @@ -95,29 +144,45 @@ { Get-JiraFilter -Id 12345 } | Should Not Throw Assert-MockCalled -CommandName ConvertTo-JiraFilter -ModuleName JiraPS } + + It "Finds all favorite filters of the user" { + { Get-JiraFilter -Favorite } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/filter/favourite'} + } } Context "Input testing" { - $sampleFilter = ConvertTo-JiraFilter ( ConvertFrom-Json $response ) + $sampleFilter = ConvertTo-JiraFilter (ConvertFrom-Json $responseFilter) It "Accepts a filter ID for the -Filter parameter" { - { Get-JiraFilter -Id 12345 } | Should Not Throw + { Get-JiraFilter -Id "12345" } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "Accepts a filter ID without the -Filter parameter" { + { Get-JiraFilter "12345" } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Accepts multiple filter IDs to the -Filter parameter" { { Get-JiraFilter -Id '12345', '67890' } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/filter/12345'} Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/filter/67890'} } It "Accepts a JiraPS.Filter object to the InputObject parameter" { { Get-JiraFilter -InputObject $sampleFilter } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*rest/api/*/filter/12844'} } It "Accepts a JiraPS.Filter object via pipeline" { { $sampleFilter | Get-JiraFilter } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*rest/api/*/filter/12844'} } } diff --git a/docs/en-US/commands/Get-JiraFilter.md b/docs/en-US/commands/Get-JiraFilter.md index 15d72777..d6a080d4 100644 --- a/docs/en-US/commands/Get-JiraFilter.md +++ b/docs/en-US/commands/Get-JiraFilter.md @@ -27,6 +27,12 @@ Get-JiraFilter [-Id] [-Credential ] [ Get-JiraFilter -InputObject [-Credential ] [] ``` +### MyFavorite + +```powershell +Get-JiraFilter -Favorite [-Credential ] [] +``` + ## DESCRIPTION This function returns information about a filter in JIRA, including the JQL syntax of the filter, its owner, and sharing status. @@ -55,6 +61,15 @@ $filterObject | Get-JiraFilter Gets the information of a filter by providing a filter object + +### EXAMPLE 3 + +```powershell +Get-JiraFilter -Favorite +``` + +Gets all filters makes as "favorite" by the user + ## PARAMETERS ### -Id @@ -89,6 +104,22 @@ Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` +### -Favorite + +Fetch all filters marked as favorite by the user + +```yaml +Type: SwitchParameter +Parameter Sets: MyFavorite +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Credential Credentials to use to connect to JIRA. @@ -127,6 +158,10 @@ This function requires either the `-Credential` parameter to be passed or a pers See `New-JiraSession` for more details. If neither are supplied, this function will run with anonymous access to JIRA. -Remaining operations for `filter` have not yet been implemented in the module. - ## RELATED LINKS + +[New-JiraFilter](../New-JiraFilter/) + +[Set-JiraFilter](../Set-JiraFilter/) + +[Remove-JiraFilter](../Remove-JiraFilter/) From 109117072a11149e1621361afc6ef8883917d3d3 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 13:40:47 +0200 Subject: [PATCH 03/83] Added Remove-JiraFilter --- JiraPS/Public/Remove-JiraFilter.ps1 | 39 +++++++ Tests/Remove-JiraFilter.Tests.ps1 | 136 ++++++++++++++++++++++ docs/en-US/commands/Remove-JiraFilter.md | 138 +++++++++++++++++++++++ 3 files changed, 313 insertions(+) create mode 100644 JiraPS/Public/Remove-JiraFilter.ps1 create mode 100644 Tests/Remove-JiraFilter.Tests.ps1 create mode 100644 docs/en-US/commands/Remove-JiraFilter.md diff --git a/JiraPS/Public/Remove-JiraFilter.ps1 b/JiraPS/Public/Remove-JiraFilter.ps1 new file mode 100644 index 00000000..e5500b45 --- /dev/null +++ b/JiraPS/Public/Remove-JiraFilter.ps1 @@ -0,0 +1,39 @@ +function Remove-JiraFilter { + [CmdletBinding( ConfirmImpact = "Medium", SupportsShouldProcess )] + param( + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [PSTypeName('JiraPS.Filter')] + $InputObject, + + [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 ($filter in $InputObject) { + $parameter = @{ + URI = $filter.RestURL + Method = "DELETE" + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($filter.Name, "Deleting Filter")) { + Invoke-JiraMethod @parameter + } + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/Tests/Remove-JiraFilter.Tests.ps1 b/Tests/Remove-JiraFilter.Tests.ps1 new file mode 100644 index 00000000..54f36423 --- /dev/null +++ b/Tests/Remove-JiraFilter.Tests.ps1 @@ -0,0 +1,136 @@ +Describe 'Get-JiraFilter' { + BeforeAll { + Remove-Module JiraPS + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + #region Definitions + $jiraServer = "https://jira.example.com" + + $responseFilter = @" +{ + "self": "$jiraServer/rest/api/latest/filter/12844", + "id": "12844", + "name": "All JIRA Bugs", + "owner": { + "self": "$jiraServer/rest/api/2/user?username=scott@atlassian.com", + "key": "scott@atlassian.com", + "name": "scott@atlassian.com", + "avatarUrls": { + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10612", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10612", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10612", + "48x48": "$jiraServer/secure/useravatar?avatarId=10612" + }, + "displayName": "Scott Farquhar [Atlassian]", + "active": true + }, + "jql": "project = 10240 AND issuetype = 1 ORDER BY key DESC", + "viewUrl": "$jiraServer/secure/IssueNavigator.jspa?mode=hide&requestId=12844", + "searchUrl": "$jiraServer/rest/api/latest/search?jql=project+%3D+10240+AND+issuetype+%3D+1+ORDER+BY+key+DESC", + "favourite": false, + "sharePermissions": [ + { + "id": 10049, + "type": "global" + } + ], + "sharedUsers": { + "size": 0, + "items": [], + "max-results": 1000, + "start-index": 0, + "end-index": 0 + }, + "subscriptions": { + "size": 0, + "items": [], + "max-results": 1000, + "start-index": 0, + "end-index": 0 + } +} +"@ + #endregion Definitions + + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { + $jiraServer + } + + Mock ConvertTo-JiraFilter -ModuleName JiraPS { + foreach ($i in $InputObject) { + $i.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $i | Add-Member -MemberType AliasProperty -Name 'RestURL' -Value 'self' + $i + } + } + + Mock Get-JiraFilter -ModuleName JiraPS { + foreach ($i in $Id) { + ConvertTo-JiraFilter (ConvertFrom-Json $responseFilter) + } + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Delete' -and $URI -like "$jiraServer/rest/api/*/filter/*"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + ConvertFrom-Json $responseFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + + Context "Sanity checking" { + $command = Get-Command -Name Get-JiraFilter + + defParam $command 'InputObject' + defParam $command 'Credential' + } + + Context "Behavior testing" { + It "Invokes the Jira API to delete a filter" { + Get-JiraFilter -Id 12844 | Remove-JiraFilter #} | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Delete' -and $URI -like '*/rest/api/*/filter/12844'} + } + } + + Context "Input testing" { + It "Accepts a filter object for the -InputObject parameter" { + { Remove-JiraFilter -InputObject (Get-JiraFilter "12345") } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "Accepts a filter object without the -InputObject parameter" { + { Remove-JiraFilter (Get-JiraFilter "12345") } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "Accepts multiple filter objects to the -Filter parameter" { + { Remove-JiraFilter -InputObject (Get-JiraFilter 12345,12345) } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "Accepts a JiraPS.Filter object via pipeline" { + { Get-JiraFilter 12345,12345 | Remove-JiraFilter } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "fails if something other than [JiraPS.Filter] is provided" { + { "12345" | Remove-JiraFilter -ErrorAction Stop } | Should Throw + { Remove-JiraFilter "12345" -ErrorAction Stop} | Should Throw + } + } + } +} diff --git a/docs/en-US/commands/Remove-JiraFilter.md b/docs/en-US/commands/Remove-JiraFilter.md new file mode 100644 index 00000000..35b93506 --- /dev/null +++ b/docs/en-US/commands/Remove-JiraFilter.md @@ -0,0 +1,138 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/Remove-JiraFilter/ +locale: en-US +schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Remove-JiraFilter/ +--- +# Remove-JiraFilter + +## SYNOPSIS + +Removes an existing filter. + +## SYNTAX + +```powershell +Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] [] +``` + +## DESCRIPTION + +This function will remove a filter from Jira. +Deleting a filter removed is permanently from Jira. + +## EXAMPLES + +### Example 1 + +```powershell +Remove-JiraFilter -InputObject (Get-JiraFilter "12345") +``` + +Removes the filter `12345` from Jira. + +### Example 2 + +```powershell +$filter = Get-JiraFilter "12345", "98765" +Remove-JiraFilter -InputObject $filter +``` + +Removes two filters (`12345` and `98765`) from Jira. + +### Example 3 + +```powershell +Get-JiraFilter "12345", "98765" | Remove-JiraFilter +``` + +Removes two filters (`12345` and `98765`) from Jira. + +### Example 4 + +```powershell +Get-JiraFilter -Favorite | Remove-JiraFilter -Confirm +``` + +Asks for each favorite filter confirmation to delete it. + +## PARAMETERS + +### -InputObject + +Filter object to be deleted. + +Object can be retrieved with `Get-JiraFilter` + +```yaml +Type: JiraPS.Filter +Parameter Sets: (All) +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +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.Filter + +## OUTPUTS + +## 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-JiraFilter](../Get-JiraFilter/) + +[New-JiraFilter](../New-JiraFilter/) + +[Set-JiraFilter](../Set-JiraFilter/) From 96e892f861ef85dfbf74b022b08ef322bf009f86 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 15:06:01 +0200 Subject: [PATCH 04/83] Added Set-JiraFilter --- JiraPS/Public/Set-JiraFilter.ps1 | 75 +++++++ Tests/Set-JiraFilter.Tests.ps1 | 307 ++++++++++++++++++++++++++ docs/en-US/commands/Set-JiraFilter.md | 226 +++++++++++++++++++ 3 files changed, 608 insertions(+) create mode 100644 JiraPS/Public/Set-JiraFilter.ps1 create mode 100644 Tests/Set-JiraFilter.Tests.ps1 create mode 100644 docs/en-US/commands/Set-JiraFilter.md diff --git a/JiraPS/Public/Set-JiraFilter.ps1 b/JiraPS/Public/Set-JiraFilter.ps1 new file mode 100644 index 00000000..68902f3a --- /dev/null +++ b/JiraPS/Public/Set-JiraFilter.ps1 @@ -0,0 +1,75 @@ +function Set-JiraFilter { + [CmdletBinding( SupportsShouldProcess )] + param( + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [PSTypeName('JiraPS.Filter')] + $InputObject, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter()] + [String] + $Description, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String] + $JQL, + + [Parameter()] + [Alias('Favourite')] + [Bool] + $Favorite, + + [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)" + + $requestBody = @{} + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Name")) { + $requestBody["name"] = $Name + } + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Description")) { + $requestBody["description"] = $Description + } + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("JQL")) { + $requestBody["jql"] = $JQL + } + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Favorite")) { + $requestBody["favourite"] = $Favorite + } + + if ($requestBody.Keys.Count) { + $parameter = @{ + URI = $InputObject.RestURL + Method = "PUT" + Body = ConvertTo-Json -InputObject $requestBody + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($InputObject.Name, "Update Filter")) { + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraFilter -InputObject $result) + } + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/Tests/Set-JiraFilter.Tests.ps1 b/Tests/Set-JiraFilter.Tests.ps1 new file mode 100644 index 00000000..7f550f76 --- /dev/null +++ b/Tests/Set-JiraFilter.Tests.ps1 @@ -0,0 +1,307 @@ +Describe 'Set-JiraFilter' { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + #region Definitions + $jiraServer = "https://jira.example.com" + + $responseFilter = @" +{ + "self": "$jiraServer/rest/api/latest/filter/12844", + "id": "12844", + "name": "All JIRA Bugs", + "owner": { + "self": "$jiraServer/rest/api/2/user?username=scott@atlassian.com", + "key": "scott@atlassian.com", + "name": "scott@atlassian.com", + "avatarUrls": { + "16x16": "$jiraServer/secure/useravatar?size=xsmall&avatarId=10612", + "24x24": "$jiraServer/secure/useravatar?size=small&avatarId=10612", + "32x32": "$jiraServer/secure/useravatar?size=medium&avatarId=10612", + "48x48": "$jiraServer/secure/useravatar?avatarId=10612" + }, + "displayName": "Scott Farquhar [Atlassian]", + "active": true + }, + "jql": "project = 10240 AND issuetype = 1 ORDER BY key DESC", + "viewUrl": "$jiraServer/secure/IssueNavigator.jspa?mode=hide&requestId=12844", + "searchUrl": "$jiraServer/rest/api/latest/search?jql=project+%3D+10240+AND+issuetype+%3D+1+ORDER+BY+key+DESC", + "favourite": false, + "sharePermissions": [ + { + "id": 10049, + "type": "global" + } + ], + "sharedUsers": { + "size": 0, + "items": [], + "max-results": 1000, + "start-index": 0, + "end-index": 0 + }, + "subscriptions": { + "size": 0, + "items": [], + "max-results": 1000, + "start-index": 0, + "end-index": 0 + } +} +"@ + #endregion Definitions + + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { + $jiraServer + } + + Mock ConvertTo-JiraFilter -ModuleName JiraPS { + foreach ($i in $InputObject) { + $i.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $i | Add-Member -MemberType AliasProperty -Name 'RestURL' -Value 'self' + $i + } + } + + Mock Get-JiraFilter -ModuleName JiraPS { + foreach ($i in $Id) { + ConvertTo-JiraFilter (ConvertFrom-Json $responseFilter) + } + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Put' -and $URI -like "$jiraServer/rest/api/*/filter/*"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'Body' + ConvertFrom-Json $responseFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + + Context "Sanity checking" { + $command = Get-Command -Name Set-JiraFilter + + defParam $command 'InputObject' + defParam $command 'Name' + defParam $command 'Description' + defParam $command 'JQL' + defParam $command 'Favorite' + defParam $command 'Credential' + + defAlias $command 'Favourite' 'Favorite' + } + + Context "Behavior testing" { + It "Invokes the Jira API to update a filter" { + { + $newData = @{ + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + Favorite = $true + } + Get-JiraFilter -Id 12844 | Set-JiraFilter @newData + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Put' -and + $URI -like '*/rest/api/*/filter/12844' -and + $Body -match "`"name`":\s*`"newName`"" -and + $Body -match "`"description`":\s*`"newDescription`"" -and + $Body -match "`"jql`":\s*`"newJQL`"" -and + $Body -match "`"favourite`":\s*true" + } + } + + It "Can set the Description to Empty" { + { + $newData = @{ + Description = "" + } + Get-JiraFilter -Id 12844 | Set-JiraFilter @newData + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Put' -and + $URI -like '*/rest/api/*/filter/12844' -and + $Body -match "`"description`":\s*`"`"" + } + } + + It "Skips the filter if no value was changed" { + { Get-JiraFilter -Id 12844 | Set-JiraFilter } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 0 -Scope It + } + } + + Context "Input testing" { + It "accepts a filter object for the -InputObject parameter" { + { Set-JiraFilter -InputObject (Get-JiraFilter "12345") -Name "test" } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "accepts a filter object without the -InputObject parameter" { + { Set-JiraFilter (Get-JiraFilter "12345") -Name "test" } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "fails with multiple filter objects to the -Filter parameter" { + { Set-JiraFilter -InputObject (Get-JiraFilter 12345, 12345) -Name "test" } | Should Throw + } + + It "accepts a JiraPS.Filter object via pipeline" { + { Get-JiraFilter 12345, 12345 | Set-JiraFilter -Name "test" } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "fails if something other than [JiraPS.Filter] is provided to InputObject" { + { "12345" | Set-JiraFilter -ErrorAction Stop } | Should Throw + { Set-JiraFilter "12345" -ErrorAction Stop} | Should Throw + } + + It "accepts -InputObject" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 0 -Scope It + } + It "accepts -InputObject and -Name" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Description" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Description = "newDescription" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -JQL" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + JQL = "newJQL" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Favorite" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Favorite = $true + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Name and -Description" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + Description = "newDescription" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Name and -JQL" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + JQL = "newJQL" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Name and -Favorite" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + Favorite = $true + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Name and -Description and -JQL" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Name and -Description and -Favorite" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + Description = "newDescription" + Favorite = $true + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "accepts -InputObject and -Name and -Description and -JQL and -Favorite" { + { + $parameter = @{ + InputObject = Get-JiraFilter "12345" + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + Favorite = $true + } + Set-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + } + } +} diff --git a/docs/en-US/commands/Set-JiraFilter.md b/docs/en-US/commands/Set-JiraFilter.md new file mode 100644 index 00000000..13e954dd --- /dev/null +++ b/docs/en-US/commands/Set-JiraFilter.md @@ -0,0 +1,226 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/Set-JiraFilter/ +locale: en-US +schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Set-JiraFilter/ +--- +# Set-JiraFilter + +## SYNOPSIS + +Make changes to an existing Filter. + +## SYNTAX + +```powershell +Set-JiraFilter [-InputObject] [[-Name] ] [[-Description] ] [[-JQL] ] + [-Favorite] [[-Credential] ] [-WhatIf] [-Confirm] [] +``` + +## DESCRIPTION + +Make changes to an existing Filter. + +If no changing parameter is provided, no action will be performed. + +## EXAMPLES + +### Example 1 + +```powershell +Set-JiraFilter -InputObject (Get-JiraFilter "12345") -Name "NewName" +``` + +Changes the name of filter "12345" to "NewName" + +### Example 2 + +```powershell +$filterData = @{ + InputObject = Get-JiraFilter "12345" + Description = "A new description" + JQL = "project = TV AND type = Bug" + Favorite = $true +} +Set-JiraFilter @filterData +``` + +Changes the description and JQL of filter "12345" and make it a favorite + +### Example 3 + +```powershell +Get-JiraFilter -Favorite | + Where name -notlike "My*" | + Set-JiraFilter -Favorite $false +``` + +Remove all favorite filters where the name does not start with "My" + +## PARAMETERS + +### -InputObject + +Filter object to be changed. + +Object can be retrieved with `Get-JiraFilter` + +```yaml +Type: Object +Parameter Sets: (All) +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -Name + +New value for the filter's Name. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Description + +New value for the filter's Description. + +Can be an empty string. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -JQL + +New value for the filter's JQL string which the filter uses for matching issues. + +More about JQL at + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 3 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Favorite + +Boolean flag if the filter should be marked as favorite for the user. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: Favourite + +Required: False +Position: Named +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: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +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.Filter] / [String] + +## OUTPUTS + +### [JiraPS.Filter] + +## 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-JiraFilter](../Get-JiraFilter/) + +[New-JiraFilter](../New-JiraFilter/) + +[Remove-JiraFilter](../Remove-JiraFilter/) From c13278d92fe1912f3a3f3e7c8ba5c2f487268878 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 18:59:55 +0200 Subject: [PATCH 05/83] Added New-JiraFilter --- JiraPS/Public/New-JiraFilter.ps1 | 67 +++++++++ Tests/New-JiraFilter.Tests.ps1 | 129 ++++++++++++++++ docs/en-US/commands/New-JiraFilter.md | 202 ++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 JiraPS/Public/New-JiraFilter.ps1 create mode 100644 Tests/New-JiraFilter.Tests.ps1 create mode 100644 docs/en-US/commands/New-JiraFilter.md diff --git a/JiraPS/Public/New-JiraFilter.ps1 b/JiraPS/Public/New-JiraFilter.ps1 new file mode 100644 index 00000000..864039ff --- /dev/null +++ b/JiraPS/Public/New-JiraFilter.ps1 @@ -0,0 +1,67 @@ +function New-JiraFilter { + [CmdletBinding( SupportsShouldProcess )] + param( + [Parameter( Mandatory, ValueFromPipelineByPropertyName )] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter( ValueFromPipelineByPropertyName )] + [String] + $Description, + + [Parameter( Mandatory, ValueFromPipelineByPropertyName )] + [ValidateNotNullOrEmpty()] + [String] + $JQL, + + [Parameter( ValueFromPipelineByPropertyName )] + [Alias('Favourite')] + [Switch] + $Favorite, + + [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 + + $resourceURi = "$server/rest/api/latest/filter" + } + + process { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + $requestBody = @{ + Name = $Name + JQL = $JQL + } + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Description")) { + $requestBody["description"] = $Description + } + $requestBody["favourite"] = [Bool]$Favorite + + $parameter = @{ + URI = $resourceURi + Method = "POST" + Body = ConvertTo-Json -InputObject $requestBody + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($Name, "Creating new Filter")) { + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraFilter -InputObject $result) + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/Tests/New-JiraFilter.Tests.ps1 b/Tests/New-JiraFilter.Tests.ps1 new file mode 100644 index 00000000..d198f004 --- /dev/null +++ b/Tests/New-JiraFilter.Tests.ps1 @@ -0,0 +1,129 @@ +Describe 'New-JiraFilter' { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + #region Definitions + $jiraServer = "https://jira.example.com" + + $responseFilter = @" +{ + "self": "$jiraServer/rest/api/latest/filter/12844", + "id": "12844", + "name": "{0}", + "jql": "{1}", + "favourite": false +} +"@ + #endregion Definitions + + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { + $jiraServer + } + + Mock ConvertTo-JiraFilter -ModuleName JiraPS { + $i = (ConvertFrom-Json $responseFilter) + $i.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $i | Add-Member -MemberType AliasProperty -Name 'RestURL' -Value 'self' + $i + } + + Mock Get-JiraFilter -ModuleName JiraPS { + ConvertTo-JiraFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Post' -and $URI -like "$jiraServer/rest/api/*/filter"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'Body' + ConvertFrom-Json $responseFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + + Context "Sanity checking" { + $command = Get-Command -Name New-JiraFilter + + defParam $command 'Name' + defParam $command 'Description' + defParam $command 'JQL' + defParam $command 'Favorite' + defParam $command 'Credential' + + defAlias $command 'Favourite' 'Favorite' + } + + Context "Behavior testing" { + It "Invokes the Jira API to create a filter" { + { + $newData = @{ + Name = "myName" + Description = "myDescription" + JQL = "myJQL" + Favorite = $true + } + New-JiraFilter @newData + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter' -and + $Body -match "`"name`":\s*`"myName`"" -and + $Body -match "`"description`":\s*`"myDescription`"" -and + $Body -match "`"jql`":\s*`"myJQL`"" -and + $Body -match "`"favourite`":\s*true" + } + } + } + + Context "Input testing" { + It "-Name and -JQL" { + { + $parameter = @{ + Name = "newName" + JQL = "newJQL" + } + New-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "-Name and -Description and -JQL" { + { + $parameter = @{ + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + } + New-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "-Name and -Description and -JQL and -Favorite" { + { + $parameter = @{ + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + Favorite = $true + } + New-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "maps the properties of an object to the parameters" { + { Get-JiraFilter "12345" | New-JiraFilter } | Should Not Throw + } + } + } +} diff --git a/docs/en-US/commands/New-JiraFilter.md b/docs/en-US/commands/New-JiraFilter.md new file mode 100644 index 00000000..d36c5445 --- /dev/null +++ b/docs/en-US/commands/New-JiraFilter.md @@ -0,0 +1,202 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/New-JiraFilter/ +locale: en-US +schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/New-JiraFilter/ +--- +# New-JiraFilter + +## SYNOPSIS + +Create a new Jira filter. + +## SYNTAX + +```powershell +New-JiraFilter -Name [-Description ] -JQL [-Favorite] [-Credential ] + [-WhatIf] [-Confirm] [] +``` + +## DESCRIPTION + +Create a new Jira filter. + +## EXAMPLES + +### Example 1 + +```powershell +New-JiraFilter -Name "My Bugs" -JQL "type = Bug and assignee = currentuser()" +``` + +Creates a new filter named "My Bugs" + +### Example 2 + +```powershell +New-JiraFilter -Name "My Bugs" -JQL "type = Bug and assignee = currentuser()" -Favorite +``` + +Creates a new filter named "My Bugs" and stores it as favorite + +### Example 3 + +```powershell +$splatNewFilter = @{ + Name = "My Bugs" + Description = "collections of bugs assigned to me" + JQL = "type = Bug and assignee = currentuser()" + Favorite = $true +} +New-JiraFilter @splatNewFilter +``` + +Creates a new filter named "My Bugs" using splatting + +## PARAMETERS + +### -Name + +Name of the filter. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -Description + +Description for the filter. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -JQL + +JQL string which the filter uses for matching issues. + +More about JQL at + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -Favorite + +Make this new filter a favorite of the user. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: Favourite + +Required: False +Position: Named +Default value: None +Accept pipeline input: True (ByPropertyName) +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: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +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 + +### [System.String] + +## OUTPUTS + +### [JiraPS.Filter] + +## 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-JiraFilter](../Get-JiraFilter/) + +[Set-JiraFilter](../Set-JiraFilter/) + +[Remove-JiraFilter](../Remove-JiraFilter/) From 0a249755b7337075c306fac7aa6ff863ff90fbb1 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 19:00:52 +0200 Subject: [PATCH 06/83] Fixed documentation of functions --- docs/en-US/commands/Get-JiraFilter.md | 4 ++-- docs/en-US/commands/Set-JiraFilter.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en-US/commands/Get-JiraFilter.md b/docs/en-US/commands/Get-JiraFilter.md index d6a080d4..7ff88bf8 100644 --- a/docs/en-US/commands/Get-JiraFilter.md +++ b/docs/en-US/commands/Get-JiraFilter.md @@ -111,9 +111,9 @@ Fetch all filters marked as favorite by the user ```yaml Type: SwitchParameter Parameter Sets: MyFavorite -Aliases: +Aliases: Favourite -Required: False +Required: True Position: Named Default value: False Accept pipeline input: False diff --git a/docs/en-US/commands/Set-JiraFilter.md b/docs/en-US/commands/Set-JiraFilter.md index 13e954dd..1ceb28cc 100644 --- a/docs/en-US/commands/Set-JiraFilter.md +++ b/docs/en-US/commands/Set-JiraFilter.md @@ -69,7 +69,7 @@ Filter object to be changed. Object can be retrieved with `Get-JiraFilter` ```yaml -Type: Object +Type: JiraPS.Filter Parameter Sets: (All) Aliases: @@ -137,7 +137,7 @@ Accept wildcard characters: False Boolean flag if the filter should be marked as favorite for the user. ```yaml -Type: SwitchParameter +Type: Boolean Parameter Sets: (All) Aliases: Favourite From 81516dde7229e8e8080f93a71131887b8fbde15b Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 19:02:05 +0200 Subject: [PATCH 07/83] Updated documentation tests to allow for type declaration of `[PSTypeName('JiraPS.Filter')]` --- Tests/JiraPS.Help.Tests.ps1 | 5 +++++ docs/en-US/commands/Get-JiraVersion.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Tests/JiraPS.Help.Tests.ps1 b/Tests/JiraPS.Help.Tests.ps1 index 097d9ca1..46bf7d6d 100644 --- a/Tests/JiraPS.Help.Tests.ps1 +++ b/Tests/JiraPS.Help.Tests.ps1 @@ -181,6 +181,11 @@ foreach ($command in $commands) { # Parameter type in Help should match code It "help for $commandName has correct parameter type for $parameterName" { $codeType = $parameter.ParameterType.Name + if ($codeType -eq "Object") { + if (($parameter.Attributes) -and ($parameter.Attributes | Get-Member -Name PSTypeName)) { + $codeType = $parameter.Attributes[0].PSTypeName + } + } # To avoid calling Trim method on a null object. $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } if ($helpType -eq "PSCustomObject") { $helpType = "PSObject" } diff --git a/docs/en-US/commands/Get-JiraVersion.md b/docs/en-US/commands/Get-JiraVersion.md index 5c282363..4e1759e6 100644 --- a/docs/en-US/commands/Get-JiraVersion.md +++ b/docs/en-US/commands/Get-JiraVersion.md @@ -101,7 +101,7 @@ Accept wildcard characters: False A Version object to search for ```yaml -Type: Object +Type: JiraPS.Version Parameter Sets: byInputVersion Aliases: @@ -133,7 +133,7 @@ Accept wildcard characters: False A Project Object to search ```yaml -Type: Object +Type: JiraPS.Project Parameter Sets: byInputProject Aliases: From c63790aba96ae38b254797b6db3a8c9a4d0a4db7 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 26 May 2018 19:15:40 +0200 Subject: [PATCH 08/83] Reverted changes to `Credential` parameter --- JiraPS/Public/Get-JiraIssue.ps1 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 2b375bff..732633c6 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -81,11 +81,8 @@ function Get-JiraIssue { [Int] $PageSize = 50, - [Parameter()] - [ValidateNotNull()] [System.Management.Automation.PSCredential] - [System.Management.Automation.Credential()] - $Credential = [System.Management.Automation.PSCredential]::Empty + $Credential ) begin { From b00e5d5729b7a32540e417d9e7a53b79a412c8eb Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 27 May 2018 12:41:33 +0200 Subject: [PATCH 09/83] Improved handling of Credential parameter --- JiraPS/Private/Resolve-JiraIssueObject.ps1 | 6 ++-- JiraPS/Public/Add-JiraGroupMember.ps1 | 6 ++-- JiraPS/Public/Add-JiraIssueAttachment.ps1 | 6 ++-- JiraPS/Public/Add-JiraIssueComment.ps1 | 6 ++-- JiraPS/Public/Add-JiraIssueLink.ps1 | 6 ++-- JiraPS/Public/Add-JiraIssueWatcher.ps1 | 6 ++-- JiraPS/Public/Add-JiraIssueWorklog.ps1 | 6 ++-- JiraPS/Public/Get-JiraComponent.ps1 | 6 ++-- JiraPS/Public/Get-JiraField.ps1 | 6 ++-- JiraPS/Public/Get-JiraFilter.ps1 | 6 ++-- JiraPS/Public/Get-JiraGroup.ps1 | 6 ++-- JiraPS/Public/Get-JiraGroupMember.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssue.ps1 | 7 ++-- JiraPS/Public/Get-JiraIssueAttachment.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssueComment.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssueEditMetadata.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssueLink.ps1 | 5 ++- JiraPS/Public/Get-JiraIssueLinkType.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssueType.ps1 | 6 ++-- JiraPS/Public/Get-JiraIssueWatcher.ps1 | 6 ++-- JiraPS/Public/Get-JiraPriority.ps1 | 6 ++-- JiraPS/Public/Get-JiraProject.ps1 | 6 ++-- JiraPS/Public/Get-JiraRemoteLink.ps1 | 6 ++-- JiraPS/Public/Get-JiraServerInformation.ps1 | 6 ++-- JiraPS/Public/Get-JiraUser.ps1 | 6 ++-- JiraPS/Public/Get-JiraVersion.ps1 | 6 ++-- JiraPS/Public/Invoke-JiraIssueTransition.ps1 | 6 ++-- JiraPS/Public/Invoke-JiraMethod.ps1 | 12 ++++--- JiraPS/Public/New-JiraGroup.ps1 | 6 ++-- JiraPS/Public/New-JiraIssue.ps1 | 6 ++-- JiraPS/Public/New-JiraSession.ps1 | 3 +- JiraPS/Public/New-JiraUser.ps1 | 6 ++-- JiraPS/Public/New-JiraVersion.ps1 | 6 ++-- JiraPS/Public/Remove-JiraGroup.ps1 | 6 ++-- JiraPS/Public/Remove-JiraGroupMember.ps1 | 6 ++-- JiraPS/Public/Remove-JiraIssueAttachment.ps1 | 6 ++-- JiraPS/Public/Remove-JiraIssueLink.ps1 | 6 ++-- JiraPS/Public/Remove-JiraIssueWatcher.ps1 | 6 ++-- JiraPS/Public/Remove-JiraRemoteLink.ps1 | 6 ++-- JiraPS/Public/Remove-JiraUser.ps1 | 6 ++-- JiraPS/Public/Remove-JiraVersion.ps1 | 6 ++-- JiraPS/Public/Set-JiraIssue.ps1 | 6 ++-- JiraPS/Public/Set-JiraIssueLabel.ps1 | 6 ++-- JiraPS/Public/Set-JiraUser.ps1 | 6 ++-- JiraPS/Public/Set-JiraVersion.ps1 | 35 +++---------------- 46 files changed, 186 insertions(+), 122 deletions(-) diff --git a/JiraPS/Private/Resolve-JiraIssueObject.ps1 b/JiraPS/Private/Resolve-JiraIssueObject.ps1 index 737fa307..3277c889 100644 --- a/JiraPS/Private/Resolve-JiraIssueObject.ps1 +++ b/JiraPS/Private/Resolve-JiraIssueObject.ps1 @@ -28,8 +28,10 @@ function Resolve-JiraIssueObject { $InputObject, # Authentication credentials - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) # As we are not able to use proper type casting in the parameters, this is a workaround diff --git a/JiraPS/Public/Add-JiraGroupMember.ps1 b/JiraPS/Public/Add-JiraGroupMember.ps1 index fff2b5dc..fd96f8bd 100644 --- a/JiraPS/Public/Add-JiraGroupMember.ps1 +++ b/JiraPS/Public/Add-JiraGroupMember.ps1 @@ -16,8 +16,10 @@ function Add-JiraGroupMember { Once we have custom classes, this can also accept ValueFromPipeline #> - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $PassThru diff --git a/JiraPS/Public/Add-JiraIssueAttachment.ps1 b/JiraPS/Public/Add-JiraIssueAttachment.ps1 index 2b40a114..1c098d50 100644 --- a/JiraPS/Public/Add-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Add-JiraIssueAttachment.ps1 @@ -54,8 +54,10 @@ function Add-JiraIssueAttachment { [String[]] $FilePath, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $PassThru diff --git a/JiraPS/Public/Add-JiraIssueComment.ps1 b/JiraPS/Public/Add-JiraIssueComment.ps1 index f12b7b33..651d0881 100644 --- a/JiraPS/Public/Add-JiraIssueComment.ps1 +++ b/JiraPS/Public/Add-JiraIssueComment.ps1 @@ -37,8 +37,10 @@ function Add-JiraIssueComment { [String] $VisibleRole = 'All Users', - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Add-JiraIssueLink.ps1 b/JiraPS/Public/Add-JiraIssueLink.ps1 index ed8fca9c..f8a2f867 100644 --- a/JiraPS/Public/Add-JiraIssueLink.ps1 +++ b/JiraPS/Public/Add-JiraIssueLink.ps1 @@ -60,8 +60,10 @@ function Add-JiraIssueLink { [String] $Comment, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Add-JiraIssueWatcher.ps1 b/JiraPS/Public/Add-JiraIssueWatcher.ps1 index f5bd9378..ac9282ea 100644 --- a/JiraPS/Public/Add-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Add-JiraIssueWatcher.ps1 @@ -36,8 +36,10 @@ [Object] $Issue, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Add-JiraIssueWorklog.ps1 b/JiraPS/Public/Add-JiraIssueWorklog.ps1 index b9e6100b..7c164be3 100644 --- a/JiraPS/Public/Add-JiraIssueWorklog.ps1 +++ b/JiraPS/Public/Add-JiraIssueWorklog.ps1 @@ -45,8 +45,10 @@ function Add-JiraIssueWorklog { [String] $VisibleRole = 'All Users', - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraComponent.ps1 b/JiraPS/Public/Get-JiraComponent.ps1 index 04c218d7..2ad92467 100644 --- a/JiraPS/Public/Get-JiraComponent.ps1 +++ b/JiraPS/Public/Get-JiraComponent.ps1 @@ -36,8 +36,10 @@ function Get-JiraComponent { [Int[]] $ComponentId, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraField.ps1 b/JiraPS/Public/Get-JiraField.ps1 index 21697071..1ec24eff 100644 --- a/JiraPS/Public/Get-JiraField.ps1 +++ b/JiraPS/Public/Get-JiraField.ps1 @@ -5,8 +5,10 @@ [String[]] $Field, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraFilter.ps1 b/JiraPS/Public/Get-JiraFilter.ps1 index 4ca4d6b8..5588f6f8 100644 --- a/JiraPS/Public/Get-JiraFilter.ps1 +++ b/JiraPS/Public/Get-JiraFilter.ps1 @@ -37,8 +37,10 @@ [Object[]] $InputObject, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraGroup.ps1 b/JiraPS/Public/Get-JiraGroup.ps1 index 43f74bac..7a689da1 100644 --- a/JiraPS/Public/Get-JiraGroup.ps1 +++ b/JiraPS/Public/Get-JiraGroup.ps1 @@ -7,8 +7,10 @@ function Get-JiraGroup { [String[]] $GroupName, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraGroupMember.ps1 b/JiraPS/Public/Get-JiraGroupMember.ps1 index 1c0ac0df..d204889a 100644 --- a/JiraPS/Public/Get-JiraGroupMember.ps1 +++ b/JiraPS/Public/Get-JiraGroupMember.ps1 @@ -35,8 +35,10 @@ function Get-JiraGroupMember { [Int] $MaxResults = 0, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 552a3af7..62ffc564 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -3,6 +3,7 @@ function Get-JiraIssue { param( [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByIssueKey' )] [ValidateNotNullOrEmpty()] + [Alias('Issue')] [String[]] $Key, @@ -80,8 +81,10 @@ function Get-JiraIssue { [Int] $PageSize = 50, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueAttachment.ps1 b/JiraPS/Public/Get-JiraIssueAttachment.ps1 index e1241e41..d093f11d 100644 --- a/JiraPS/Public/Get-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Get-JiraIssueAttachment.ps1 @@ -31,8 +31,10 @@ function Get-JiraIssueAttachment { [String] $FileName, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueComment.ps1 b/JiraPS/Public/Get-JiraIssueComment.ps1 index 17c8bb53..b61b3824 100644 --- a/JiraPS/Public/Get-JiraIssueComment.ps1 +++ b/JiraPS/Public/Get-JiraIssueComment.ps1 @@ -28,8 +28,10 @@ function Get-JiraIssueComment { [Object] $Issue, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 b/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 index 3caf79f1..d0241adb 100644 --- a/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 +++ b/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 @@ -9,8 +9,10 @@ function Get-JiraIssueCreateMetadata { [String] $IssueType, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 b/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 index fa567744..2013156d 100644 --- a/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 +++ b/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 @@ -9,8 +9,10 @@ function Get-JiraIssueEditMetadata { Once we have custom classes, this should be a JiraPS.Issue #> - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueLink.ps1 b/JiraPS/Public/Get-JiraIssueLink.ps1 index 93c84f2f..99b00204 100644 --- a/JiraPS/Public/Get-JiraIssueLink.ps1 +++ b/JiraPS/Public/Get-JiraIssueLink.ps1 @@ -5,7 +5,10 @@ function Get-JiraIssueLink { [Int[]] $Id, - [PSCredential] $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueLinkType.ps1 b/JiraPS/Public/Get-JiraIssueLinkType.ps1 index 6beecaca..0496b427 100644 --- a/JiraPS/Public/Get-JiraIssueLinkType.ps1 +++ b/JiraPS/Public/Get-JiraIssueLinkType.ps1 @@ -27,8 +27,10 @@ function Get-JiraIssueLinkType { [Object] $LinkType, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueType.ps1 b/JiraPS/Public/Get-JiraIssueType.ps1 index 0c9e67bf..70cea3ea 100644 --- a/JiraPS/Public/Get-JiraIssueType.ps1 +++ b/JiraPS/Public/Get-JiraIssueType.ps1 @@ -5,8 +5,10 @@ [String[]] $IssueType, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraIssueWatcher.ps1 b/JiraPS/Public/Get-JiraIssueWatcher.ps1 index ab3b74f2..fdd9294c 100644 --- a/JiraPS/Public/Get-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Get-JiraIssueWatcher.ps1 @@ -28,8 +28,10 @@ [Object] $Issue, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraPriority.ps1 b/JiraPS/Public/Get-JiraPriority.ps1 index 784bad8c..311d9a07 100644 --- a/JiraPS/Public/Get-JiraPriority.ps1 +++ b/JiraPS/Public/Get-JiraPriority.ps1 @@ -5,8 +5,10 @@ function Get-JiraPriority { [Int[]] $Id, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraProject.ps1 b/JiraPS/Public/Get-JiraProject.ps1 index 195a9fd3..6cf06f30 100644 --- a/JiraPS/Public/Get-JiraProject.ps1 +++ b/JiraPS/Public/Get-JiraProject.ps1 @@ -5,8 +5,10 @@ function Get-JiraProject { [String[]] $Project, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraRemoteLink.ps1 b/JiraPS/Public/Get-JiraRemoteLink.ps1 index ece03eca..daf3d3fc 100644 --- a/JiraPS/Public/Get-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Get-JiraRemoteLink.ps1 @@ -31,8 +31,10 @@ function Get-JiraRemoteLink { [Int] $LinkId, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraServerInformation.ps1 b/JiraPS/Public/Get-JiraServerInformation.ps1 index 0f1cbb6b..2f118b51 100644 --- a/JiraPS/Public/Get-JiraServerInformation.ps1 +++ b/JiraPS/Public/Get-JiraServerInformation.ps1 @@ -1,8 +1,10 @@ function Get-JiraServerInformation { [CmdletBinding()] param( - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraUser.ps1 b/JiraPS/Public/Get-JiraUser.ps1 index cc2bdc1f..51537075 100644 --- a/JiraPS/Public/Get-JiraUser.ps1 +++ b/JiraPS/Public/Get-JiraUser.ps1 @@ -13,8 +13,10 @@ function Get-JiraUser { [Switch] $IncludeInactive, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Get-JiraVersion.ps1 b/JiraPS/Public/Get-JiraVersion.ps1 index 9e00ba9b..088a2dd8 100644 --- a/JiraPS/Public/Get-JiraVersion.ps1 +++ b/JiraPS/Public/Get-JiraVersion.ps1 @@ -24,8 +24,10 @@ [String[]] $Name, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Invoke-JiraIssueTransition.ps1 b/JiraPS/Public/Invoke-JiraIssueTransition.ps1 index 55f7dea7..34800310 100644 --- a/JiraPS/Public/Invoke-JiraIssueTransition.ps1 +++ b/JiraPS/Public/Invoke-JiraIssueTransition.ps1 @@ -41,8 +41,10 @@ function Invoke-JiraIssueTransition { [String] $Comment, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Passthru diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 3148b294..d3a0123c 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -28,8 +28,10 @@ function Invoke-JiraMethod { [Switch] $StoreSession, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] @@ -89,10 +91,10 @@ function Invoke-JiraMethod { $splatParameters.Remove("WebSession") } - if ($session = Get-JiraSession -ErrorAction SilentlyContinue) { - if (-not ($Credential)) { + if ((-not $Credential) -or ($Credential -eq [System.Management.Automation.PSCredential]::Empty)) { + $splatParameters.Remove("Credential") + if ($session = Get-JiraSession -ErrorAction SilentlyContinue) { $splatParameters["WebSession"] = $session.WebSession - $splatParameters.Remove("Credential") } } diff --git a/JiraPS/Public/New-JiraGroup.ps1 b/JiraPS/Public/New-JiraGroup.ps1 index e2f9a94b..9d992074 100644 --- a/JiraPS/Public/New-JiraGroup.ps1 +++ b/JiraPS/Public/New-JiraGroup.ps1 @@ -6,8 +6,10 @@ [String[]] $GroupName, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/New-JiraIssue.ps1 b/JiraPS/Public/New-JiraIssue.ps1 index df817ad9..57eae3b9 100644 --- a/JiraPS/Public/New-JiraIssue.ps1 +++ b/JiraPS/Public/New-JiraIssue.ps1 @@ -37,8 +37,10 @@ function New-JiraIssue { [PSCustomObject] $Fields, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/New-JiraSession.ps1 b/JiraPS/Public/New-JiraSession.ps1 index cf5f32aa..e13aaee8 100644 --- a/JiraPS/Public/New-JiraSession.ps1 +++ b/JiraPS/Public/New-JiraSession.ps1 @@ -3,7 +3,8 @@ function New-JiraSession { [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( [Parameter( Mandatory )] - [PSCredential] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] $Credential, [Hashtable] diff --git a/JiraPS/Public/New-JiraUser.ps1 b/JiraPS/Public/New-JiraUser.ps1 index 774fa71d..8d1e1c1d 100644 --- a/JiraPS/Public/New-JiraUser.ps1 +++ b/JiraPS/Public/New-JiraUser.ps1 @@ -16,8 +16,10 @@ function New-JiraUser { [Boolean] $Notify = $true, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/New-JiraVersion.ps1 b/JiraPS/Public/New-JiraVersion.ps1 index fef2e100..2fceb764 100644 --- a/JiraPS/Public/New-JiraVersion.ps1 +++ b/JiraPS/Public/New-JiraVersion.ps1 @@ -80,8 +80,10 @@ [DateTime] $StartDate, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Remove-JiraGroup.ps1 b/JiraPS/Public/Remove-JiraGroup.ps1 index 92ff06cc..5616c8a8 100644 --- a/JiraPS/Public/Remove-JiraGroup.ps1 +++ b/JiraPS/Public/Remove-JiraGroup.ps1 @@ -28,8 +28,10 @@ [Object[]] $Group, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Force diff --git a/JiraPS/Public/Remove-JiraGroupMember.ps1 b/JiraPS/Public/Remove-JiraGroupMember.ps1 index 28f1f70e..0adaea50 100644 --- a/JiraPS/Public/Remove-JiraGroupMember.ps1 +++ b/JiraPS/Public/Remove-JiraGroupMember.ps1 @@ -55,8 +55,10 @@ function Remove-JiraGroupMember { [Object[]] $User, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $PassThru, diff --git a/JiraPS/Public/Remove-JiraIssueAttachment.ps1 b/JiraPS/Public/Remove-JiraIssueAttachment.ps1 index cb9c8ca0..873c2b57 100644 --- a/JiraPS/Public/Remove-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Remove-JiraIssueAttachment.ps1 @@ -38,8 +38,10 @@ function Remove-JiraIssueAttachment { [String[]] $FileName, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Force diff --git a/JiraPS/Public/Remove-JiraIssueLink.ps1 b/JiraPS/Public/Remove-JiraIssueLink.ps1 index 48be0107..8b9db97f 100644 --- a/JiraPS/Public/Remove-JiraIssueLink.ps1 +++ b/JiraPS/Public/Remove-JiraIssueLink.ps1 @@ -30,8 +30,10 @@ function Remove-JiraIssueLink { [Object[]] $IssueLink, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Remove-JiraIssueWatcher.ps1 b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 index bf5a66a3..cdd8492f 100644 --- a/JiraPS/Public/Remove-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 @@ -32,8 +32,10 @@ [Object] $Issue, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/JiraPS/Public/Remove-JiraRemoteLink.ps1 b/JiraPS/Public/Remove-JiraRemoteLink.ps1 index 7f82c003..d773affe 100644 --- a/JiraPS/Public/Remove-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Remove-JiraRemoteLink.ps1 @@ -32,8 +32,10 @@ function Remove-JiraRemoteLink { [Int[]] $LinkId, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Force diff --git a/JiraPS/Public/Remove-JiraUser.ps1 b/JiraPS/Public/Remove-JiraUser.ps1 index a7628322..2ad6533c 100644 --- a/JiraPS/Public/Remove-JiraUser.ps1 +++ b/JiraPS/Public/Remove-JiraUser.ps1 @@ -28,8 +28,10 @@ function Remove-JiraUser { [Object[]] $User, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Force diff --git a/JiraPS/Public/Remove-JiraVersion.ps1 b/JiraPS/Public/Remove-JiraVersion.ps1 index 94c0ebcc..3b20dc14 100644 --- a/JiraPS/Public/Remove-JiraVersion.ps1 +++ b/JiraPS/Public/Remove-JiraVersion.ps1 @@ -27,8 +27,10 @@ [Object[]] $Version, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Force diff --git a/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 3190bc9c..81c03511 100644 --- a/JiraPS/Public/Set-JiraIssue.ps1 +++ b/JiraPS/Public/Set-JiraIssue.ps1 @@ -50,8 +50,10 @@ function Set-JiraIssue { [String] $AddComment, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $PassThru diff --git a/JiraPS/Public/Set-JiraIssueLabel.ps1 b/JiraPS/Public/Set-JiraIssueLabel.ps1 index 2a726568..11b8a7b4 100644 --- a/JiraPS/Public/Set-JiraIssueLabel.ps1 +++ b/JiraPS/Public/Set-JiraIssueLabel.ps1 @@ -45,8 +45,10 @@ [Switch] $Clear, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $PassThru diff --git a/JiraPS/Public/Set-JiraUser.ps1 b/JiraPS/Public/Set-JiraUser.ps1 index 02675c94..69029ff4 100644 --- a/JiraPS/Public/Set-JiraUser.ps1 +++ b/JiraPS/Public/Set-JiraUser.ps1 @@ -60,8 +60,10 @@ function Set-JiraUser { [Hashtable] $Property, - [PSCredential] - $Credential, + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $PassThru diff --git a/JiraPS/Public/Set-JiraVersion.ps1 b/JiraPS/Public/Set-JiraVersion.ps1 index f6b1eaa3..4c74e244 100644 --- a/JiraPS/Public/Set-JiraVersion.ps1 +++ b/JiraPS/Public/Set-JiraVersion.ps1 @@ -1,25 +1,6 @@ function Set-JiraVersion { - <# - .SYNOPSIS - Modifies an existing Version in JIRA - .DESCRIPTION - This function modifies the Version for an existing Project in JIRA. - .EXAMPLE - Get-JiraVersion -Project $Project -Name "Old-Name" | Set-JiraVersion -Name 'New-Name' - This example assigns the modifies the existing version with a new name 'New-Name'. - .EXAMPLE - Get-JiraVersion -ID 162401 | Set-JiraVersion -Description 'Descriptive String' - This example assigns the modifies the existing version with a new name 'New-Name'. - .INPUTS - [JiraPS.Version] - .OUTPUTS - [JiraPS.Version] - .NOTES - This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. - #> [CmdletBinding( SupportsShouldProcess )] param( - # Version to be changed [Parameter( Mandatory, ValueFromPipeline )] [ValidateNotNullOrEmpty()] [ValidateScript( @@ -46,32 +27,24 @@ [Object[]] $Version, - # New Name of the Version. [String] $Name, - # New Description of the Version. [String] $Description, - # New value for Archived. [Bool] $Archived, - # New value for Released. [Bool] $Released, - # New Date of the release. [DateTime] $ReleaseDate, - # New Date of the user release. [DateTime] $StartDate, - # The new Project where this version should be in. - # This can be the ID of the Project, or the Project Object [ValidateScript( { if (("JiraPS.Project" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { @@ -96,10 +69,10 @@ [Object] $Project, - # Credentials to use to connect to JIRA. - # If not specified, this function will use anonymous access. - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { From 77f3ddf851bf1dad5b2986f7cc0f75c84d9dd873 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 27 May 2018 19:56:27 +0200 Subject: [PATCH 10/83] Implement paging of results in Invoke-JiraMethod --- JiraPS/JiraPS.psm1 | 20 +++ JiraPS/Private/ConvertTo-GetParameter.ps1 | 22 +++ JiraPS/Private/ConvertTo-ParameterHash.ps1 | 31 ++++ JiraPS/Public/Get-JiraIssue.ps1 | 113 ++++++------- JiraPS/Public/Invoke-JiraMethod.ps1 | 184 +++++++++++++++++---- docs/en-US/commands/Get-JiraIssue.md | 2 +- 6 files changed, 278 insertions(+), 94 deletions(-) create mode 100644 JiraPS/Private/ConvertTo-GetParameter.ps1 create mode 100644 JiraPS/Private/ConvertTo-ParameterHash.ps1 diff --git a/JiraPS/JiraPS.psm1 b/JiraPS/JiraPS.psm1 index 383636c1..1eabc652 100644 --- a/JiraPS/JiraPS.psm1 +++ b/JiraPS/JiraPS.psm1 @@ -12,8 +12,28 @@ if (!("System.Web.HttpUtility" -as [Type])) { Add-Type -Assembly System.Web } +if (!("System.Net.Http" -as [Type])) { + Add-Type -Assembly System.Net.Http +} #endregion Dependencies +#region Configuration +$script:DefaultContentType = "application/json; charset=utf-8" +$script:DefaultPageSize = 25 +$script:DefaultHeaders = @{ + "Accept" = "application/json" + "Accept-Charset" = "utf-8" +} +$script:PagingContainers = @( + "comments" + "dashboards" + "groups" + "issues" + "values" + "worklogs" +) +#endregion Configuration + #region LoadFunctions $PublicFunctions = @( Get-ChildItem -Path "$PSScriptRoot/Public/*.ps1" -ErrorAction SilentlyContinue ) $PrivateFunctions = @( Get-ChildItem -Path "$PSScriptRoot/Private/*.ps1" -ErrorAction SilentlyContinue ) diff --git a/JiraPS/Private/ConvertTo-GetParameter.ps1 b/JiraPS/Private/ConvertTo-GetParameter.ps1 new file mode 100644 index 00000000..70018373 --- /dev/null +++ b/JiraPS/Private/ConvertTo-GetParameter.ps1 @@ -0,0 +1,22 @@ +function ConvertTo-GetParameter { + <# + .SYNOPSIS + Generate the GET parameter string for an URL from a hashtable + #> + [CmdletBinding()] + param ( + [Parameter( Position = 0, Mandatory = $true, ValueFromPipeline = $true )] + [hashtable]$InputObject + ) + + process { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Making HTTP get parameter string out of a hashtable" + Write-Verbose ($InputObject | Out-String) + [string]$parameters = "?" + foreach ($key in $InputObject.Keys) { + $value = $InputObject[$key] + $parameters += "$key=$($value)&" + } + $parameters -replace ".$" + } +} diff --git a/JiraPS/Private/ConvertTo-ParameterHash.ps1 b/JiraPS/Private/ConvertTo-ParameterHash.ps1 new file mode 100644 index 00000000..1bdd42c0 --- /dev/null +++ b/JiraPS/Private/ConvertTo-ParameterHash.ps1 @@ -0,0 +1,31 @@ +function ConvertTo-ParameterHash { + [CmdletBinding( DefaultParameterSetName = 'ByString' )] + param ( + # URI from which to use the query + [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'ByUri' )] + [Uri] + $Uri, + + # Query string + [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByString' )] + [String] + $Query + ) + + process { + $GetParameter = @{} + + if ($Uri) { + $Query = $Uri.Query + } + + if ($Query -match "^\?.+") { + $Query.TrimStart("?").Split("&") | ForEach-Object { + $key, $value = $_.Split("=") + $GetParameter.Add($key, $value) + } + } + + Write-Output $GetParameter + } +} diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 62ffc564..93019358 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -1,5 +1,5 @@ function Get-JiraIssue { - [CmdletBinding(DefaultParameterSetName = 'ByIssueKey')] + [CmdletBinding( SupportsPaging, DefaultParameterSetName = 'ByIssueKey' )] param( [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByIssueKey' )] [ValidateNotNullOrEmpty()] @@ -79,7 +79,7 @@ function Get-JiraIssue { [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] [Int] - $PageSize = 50, + $PageSize = $script:DefaultPageSize, [Parameter()] [System.Management.Automation.PSCredential] @@ -92,17 +92,8 @@ function Get-JiraIssue { $server = Get-JiraConfigServer -ErrorAction Stop - if (($PSCmdlet.ParameterSetName -in @('ByJQL', 'ByFilter')) -and $MaxResults -eq 0) { - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Using loop mode to obtain all results" - $MaxResults = 1 - $loopMode = $true - } - else { - $loopMode = $false - } - $resourceURi = "$server/rest/api/latest/issue/{0}?expand=transitions" - $searchURi = "$server/rest/api/latest/search?jql={0}&validateQuery=true&expand=transitions&startAt={1}&maxResults={2}" + $searchURi = "$server/rest/api/latest/search" } process { @@ -136,70 +127,68 @@ function Get-JiraIssue { } } 'ByJQL' { - $escapedQuery = ConvertTo-URLEncoded $Query - $parameter = @{ - URI = $searchURi -f $escapedQuery, $StartIndex, $MaxResults - Method = "GET" - Credential = $Credential + URI = $searchURi + Method = "GET" + GetParameter = @{ + jql = (ConvertTo-URLEncoded $Query) + validateQuery = $true + expand = "transitions" + maxResults = $PageSize + } + OutputType = "JiraIssue" + Paging = $true + Credential = $Credential + } + # Paging + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $parameter[$_] = $PSCmdlet.PagingParameters.$_ + } + # Make `SupportsPaging` be backwards compatible + if ($StartIndex) { + $parameter["Skip"] = $StartIndex + } + if ($MaxResults) { + $parameter["First"] = $MaxResults } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - $result = Invoke-JiraMethod @parameter - - if ($result) { - # {"startAt":0,"maxResults":50,"total":0,"issues":[]} - - if ($loopMode) { - $totalResults = $result.total - - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Paging through all issues (loop mode)" - $allIssues = New-Object -TypeName System.Collections.ArrayList - - for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) { - $percentComplete = ($i / $totalResults) * 100 - Write-Progress -Activity "$($MyInvocation.MyCommand.Name)" -Status "Obtaining issues ($i - $($i + $PageSize))..." -PercentComplete $percentComplete - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Obtaining issues $i - $($i + $PageSize)..." - $thisSection = Get-JiraIssue -Query $Query -StartIndex $i -MaxResults $PageSize -Credential $Credential - foreach ($t in $thisSection) { - [void] $allIssues.Add($t) - } - } - Write-Progress -Activity "$($MyInvocation.MyCommand.Name)" -Status 'Obtaining issues' -Completed - Write-Output ($allIssues.ToArray()) - } - elseif ($result.total -gt 0) { - Write-Output (ConvertTo-JiraIssue -InputObject $result.issues) - } - else { - $errorMessage = @{ - Category = "ObjectNotFound" - CategoryActivity = "Searching for resource" - Message = "The JQL query did not return any results" - } - Write-Error @errorMessage - } - } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter } 'ByFilter' { $filterObj = Get-JiraFilter -InputObject $Filter -Credential $Credential -ErrorAction Stop - $jql = $filterObj.JQL <# #ToDo:CustomClass Once we have custom classes, this will no longer be necessary #> - # MaxResults would have been set to 1 in the Begin block if it - # was not supplied as a parameter. We don't want to explicitly - # invoke this method recursively with a MaxResults value of 1 - # if it wasn't initially provided to us. - if ($loopMode) { - Write-Output (Get-JiraIssue -Query $jql -Credential $Credential) + $parameter = @{ + URI = $filterObj.SearchUrl + Method = "GET" + GetParameter = @{ + validateQuery = $true + expand = "transitions" + maxResults = $PageSize + } + OutputType = "JiraIssue" + Paging = $true + Credential = $Credential } - else { - Write-Output (Get-JiraIssue -Query $jql -Credential $Credential -MaxResults $MaxResults) + # Paging + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $parameter[$_] = $PSCmdlet.PagingParameters.$_ + } + # Make `SupportsPaging` be backwards compatible + if ($StartIndex) { + $parameter["Skip"] = $StartIndex } + if ($MaxResults) { + $parameter["First"] = $MaxResults + } + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter } } } diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index d3a0123c..6708a356 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -1,6 +1,6 @@ function Invoke-JiraMethod { #Requires -Version 3 - [CmdletBinding()] + [CmdletBinding( SupportsPaging )] param ( [Parameter( Mandatory )] @@ -19,6 +19,10 @@ function Invoke-JiraMethod { [Hashtable] $Headers = @{}, + [Hashtable]$GetParameter = @{}, + + [Switch]$Paging, + [String] $InFile, @@ -28,6 +32,10 @@ function Invoke-JiraMethod { [Switch] $StoreSession, + [ValidateSet("JiraIssue")] + [String] + $OutputType, + [Parameter()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] @@ -38,19 +46,9 @@ function Invoke-JiraMethod { $Cmdlet = $PSCmdlet ) - begin { + end { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" - # pass input to local variable - # this allows to use the PSBoundParameters for recursion - $_headers = @{ # Set any default headers - "Accept" = "application/json" - "Accept-Charset" = "utf-8" - } - foreach ($item in $Headers.Key) { $_headers[$item] = $Headers[$item] } - } - - process { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" @@ -58,11 +56,46 @@ function Invoke-JiraMethod { # as the global PSDefaultParameterValues is not used $PSDefaultParameterValues = $global:PSDefaultParameterValues + # Construct the Headers with the folling priority: + # - Headers passes as parameters + # - User's Headers in $PSDefaultParameterValues + # - Module's default Headers + $_headers = $script:DefaultHeaders + if ($PSDefaultParameterValues.ContainsKey("Invoke-WebRequest:Headers")) { + $userSpecificHeaders = $PSDefaultParameterValues["Invoke-WebRequest:Headers"] + foreach ($item in $userSpecificHeaders.Key) { $_headers[$item] = $userSpecificHeaders[$item] } + } + foreach ($item in $Headers.Key) { $_headers[$item] = $Headers[$item] } + + # Amend query from URI with GetParameter + $uriQuery = ConvertTo-ParameterHash -Uri $Uri + foreach ($item in $uriQuery.Keys) { $GetParameter[$item] = $uriQuery[$item] } + # And remove it from URI + [Uri]$Uri = $Uri.GetLeftPart("Path") + $PaginatedUri = $Uri + + # Use default PageSize + if (-not $GetParameter.ContainsKey("maxResults")) { + $GetParameter["maxResults"] = $script:DefaultPageSize + } + + # Append GET parameters to URi + if ($PSCmdlet.PagingParameters) { + if ($PSCmdlet.PagingParameters.Skip) { + $GetParameter["startAt"] = $PSCmdlet.PagingParameters.Skip + } + if ($PSCmdlet.PagingParameters.First -lt $GetParameter["maxResults"]) { + $GetParameter["maxResults"] = $PSCmdlet.PagingParameters.First + } + } + + [Uri]$PaginatedUri = "$PaginatedUri$(ConvertTo-GetParameter $GetParameter)" + $splatParameters = @{ - Uri = $Uri + Uri = $PaginatedUri Method = $Method Headers = $_headers - ContentType = "application/json; charset=utf-8" + ContentType = $script:DefaultContentType UseBasicParsing = $true Credential = $Credential ErrorAction = "Stop" @@ -125,9 +158,8 @@ function Invoke-JiraMethod { } } - Test-ServerResponse -InputObject $webResponse -Cmdlet $Cmdlet - Write-Debug "[$($MyInvocation.MyCommand.Name)] Executed WebRequest. Access `$webResponse to see details" + Test-ServerResponse -InputObject $webResponse -Cmdlet $Cmdlet if ($webResponse) { # In PowerShellCore (v6+) the StatusCode of an exception is somewhere else @@ -137,8 +169,6 @@ function Invoke-JiraMethod { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Status code: $($statusCode)" if ($statusCode.value__ -ge 400) { - Write-Warning "Jira returned HTTP error $($statusCode.value__) - $($statusCode)" - if ((!($responseBody)) -and ($webResponse | Get-Member -Name "GetResponseStream")) { # Retrieve body of HTTP response - this contains more useful information about exactly why the error occurred $readStream = New-Object -TypeName System.IO.StreamReader -ArgumentList ($webResponse.GetResponseStream()) @@ -150,7 +180,31 @@ function Invoke-JiraMethod { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Retrieved body of HTTP response for more information about the error (`$responseBody)" Write-Debug "[$($MyInvocation.MyCommand.Name)] Got the following error as `$responseBody" - $result = ConvertFrom-Json -InputObject $responseBody + + $errorItem = [System.Management.Automation.ErrorRecord]::new( + ([System.ArgumentException]"Invalid Server Response"), + "InvalidResponse.Status$($statusCode.value__)", + [System.Management.Automation.ErrorCategory]::InvalidResult, + $responseBody + ) + + try { + $responseObject = ConvertFrom-Json -InputObject $responseBody -ErrorAction Stop + if ($responseObject.errorMessages) { + $errorItem.ErrorDetails = $responseObject.errorMessages | Out-String + } elseif ($responseObject.errors) { + $errorItem.ErrorDetails = $responseObject.errors | Out-String + } + else { + $errorItem.ErrorDetails = "An unknown error ocurred." + } + + } + catch { + $errorItem.ErrorDetails = "An unknown error ocurred." + } + + $Cmdlet.WriteError($errorItem) } } @@ -160,7 +214,86 @@ function Invoke-JiraMethod { } if ($webResponse.Content) { - $result = ConvertFrom-Json -InputObject $webResponse.Content + $response = ConvertFrom-Json ([Text.Encoding]::UTF8.GetString($webResponse.RawContentStream.ToArray())) + + if ($Paging) { + # Remove Parameters that don't need propagation + $script:PSDefaultParameterValues.Remove("$($MyInvocation.MyCommand.Name):IncludeTotalCount") + $null = $PSBoundParameters.Remove("Paging") + $null = $PSBoundParameters.Remove("Skip") + if (-not $PSBoundParameters["GetParameter"]) { + $PSBoundParameters["GetParameter"] = $GetParameter + } + + $total = 0 + do { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Invoking pagination [currentTotal: $total]" + + foreach ($container in $script:PagingContainers) { + if (($response) -and ($response | Get-Member -Name $container)) { + $result = $response.$container + } + } + + $total += $result.Count + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] New total: $total" + $pageSize = $response.maxResults + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] New pageSize: $pageSize" + + if ($total -gt $PSCmdlet.PagingParameters.First) { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Only output the first $($PSCmdlet.PagingParameters.First % $pageSize) of page" + $result = $result | Select-Object -First ($PSCmdlet.PagingParameters.First % $pageSize) + } + + $converter = "ConvertTo-$($OutputType)" + if (Test-Path function:\$converter) { + # Results shall be casted to custom objects (see ValidateSet) + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Outputting results as $($OutputType)" + Write-Output ($result | & $converter) + } + else { + Write-Output ($result) + } + + if ($total -ge $PSCmdlet.PagingParameters.First) { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] breaking as $total is more than $($PSCmdlet.PagingParameters.First)" + break + } + + # calculate the size of the next page + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] next page begins at $total" + $PSBoundParameters["GetParameter"]["startAt"] = $total + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] doesn't it? $($PSBoundParameters["GetParameter"]["startAt"])" + $expectedTotal = $PSBoundParameters["GetParameter"]["startAt"] + $pageSize + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] expecting to have $expectedTotal entries in total with next page" + if ($expectedTotal -gt $PSCmdlet.PagingParameters.First) { + $reduceBy = $expectedTotal - $PSCmdlet.PagingParameters.First + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] reducing next pagesize by $reduceBy" + $PSBoundParameters["GetParameter"]["maxResults"] = $pageSize - $reduceBy + } + + # Inquire the next page + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] about to invoke with : $($PSBoundParameters | Out-String)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] about to invoke with : $($PSBoundParameters["GetParameter"] | Out-String)" + $response = Invoke-JiraMethod @PSBoundParameters + + # Expand data container of paged results + $result = @() + foreach ($container in $script:PagingContainers) { + if (($response) -and ($response | Get-Member -Name $container)) { + $result = $response.$container + } + } + } while ($result.Count) + + if ($PSCmdlet.PagingParameters.IncludeTotalCount) { + [double]$Accuracy = 1.0 + $PSCmdlet.PagingParameters.NewTotalCount($total, $Accuracy) + } + } + else { + Write-Output $response + } } else { # No content, although statusCode < 400 @@ -173,17 +306,6 @@ function Invoke-JiraMethod { Write-Verbose "[$($MyInvocation.MyCommand.Name)] No Web result object was returned from. This is unusual!" } - if ($result) { - if (Get-Member -Name "Errors" -InputObject $result -ErrorAction SilentlyContinue) { - Resolve-JiraError $result -WriteError -Cmdlet $Cmdlet - } - else { - Write-Output $result - } - } - } - - end { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended" } } diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index b6e0e0ec..e36b56f8 100644 --- a/docs/en-US/commands/Get-JiraIssue.md +++ b/docs/en-US/commands/Get-JiraIssue.md @@ -224,7 +224,7 @@ Aliases: Required: False Position: Named -Default value: 50 +Default value: 25 Accept pipeline input: False Accept wildcard characters: False ``` From 9777e7216e2c645183ee2b91254cd4391a9428f8 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 27 May 2018 21:17:28 +0200 Subject: [PATCH 11/83] WIP --- .../ConvertTo-JiraFilterPermission.ps1 | 39 +++++ JiraPS/Private/ConvertTo-JiraProjectRole.ps1 | 29 ++++ JiraPS/Private/Resolve-FullPath.ps1 | 35 +++++ JiraPS/Public/Add-JiraFilterPermission.ps1 | 81 ++++++++++ JiraPS/Public/Get-JiraFilterPermission.ps1 | 41 +++++ JiraPS/Public/Remove-JiraFilterPermission.ps1 | 39 +++++ .../commands/Add-JiraFilterPermission.md | 141 ++++++++++++++++++ .../commands/Get-JiraFilterPermission.md | 78 ++++++++++ .../commands/Remove-JiraFilterPermission.md | 110 ++++++++++++++ 9 files changed, 593 insertions(+) create mode 100644 JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 create mode 100644 JiraPS/Private/ConvertTo-JiraProjectRole.ps1 create mode 100644 JiraPS/Private/Resolve-FullPath.ps1 create mode 100644 JiraPS/Public/Add-JiraFilterPermission.ps1 create mode 100644 JiraPS/Public/Get-JiraFilterPermission.ps1 create mode 100644 JiraPS/Public/Remove-JiraFilterPermission.ps1 create mode 100644 docs/en-US/commands/Add-JiraFilterPermission.md create mode 100644 docs/en-US/commands/Get-JiraFilterPermission.md create mode 100644 docs/en-US/commands/Remove-JiraFilterPermission.md diff --git a/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 b/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 new file mode 100644 index 00000000..bdc9b0c6 --- /dev/null +++ b/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 @@ -0,0 +1,39 @@ +function ConvertTo-JiraFilterPermission { + [CmdletBinding()] + param( + [Parameter( ValueFromPipeline )] + [PSObject[]] + $InputObject + ) + + process { + foreach ($i in $InputObject) { + Write-Debug "[$($MyInvocation.MyCommand.Name)] Converting `$InputObject to custom object" + + $props = @{ + 'ID' = $i.id + 'Type' = $i.type + 'Group' = $null + 'Project' = $null + 'Role' = $null + } + if ($i.group) { + $props["Group"] = ConvertTo-JiraGroup $i.group + } + if ($i.project) { + $props["Project"] = ConvertTo-JiraProject $i.project + } + if ($i.role) { + $props["Role"] = ConvertTo-JiraProjectRole $i.role + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'JiraPS.FilterPermission') + $result | Add-Member -MemberType ScriptMethod -Name 'ToString' -Force -Value { + Write-Output "$($this.Id)" + } + + Write-Output $result + } + } +} diff --git a/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 b/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 new file mode 100644 index 00000000..685dfea9 --- /dev/null +++ b/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 @@ -0,0 +1,29 @@ +function ConvertTo-JiraProjectRole { + [CmdletBinding()] + param( + [Parameter( ValueFromPipeline )] + [PSObject[]] + $InputObject + ) + + process { + foreach ($i in $InputObject) { + Write-Debug "[$($MyInvocation.MyCommand.Name)] Converting `$InputObject to custom object" + + $props = @{ + 'ID' = $i.id + 'Name' = $i.name + 'RestUrl' = $i.self + 'ProjectId' = $i.projectId + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'JiraPS.ProjectRole') + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Name)" + } + + Write-Output $result + } + } +} diff --git a/JiraPS/Private/Resolve-FullPath.ps1 b/JiraPS/Private/Resolve-FullPath.ps1 new file mode 100644 index 00000000..75e4af72 --- /dev/null +++ b/JiraPS/Private/Resolve-FullPath.ps1 @@ -0,0 +1,35 @@ +function Resolve-FullPath { + [CmdletBinding()] + param ( + # Path to be resolved. + # Can be realtive or absolute. + # Resolves PSDrives + [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] + [ValidateNotNullOrEmpty()] + [ValidateScript( + { + if (-not (Test-Path $_ -PathType Leaf)) { + $errorItem = [System.Management.Automation.ErrorRecord]::new( + ([System.ArgumentException]"File not found"), + 'ParameterValue.FileNotFound', + [System.Management.Automation.ErrorCategory]::ObjectNotFound, + $_ + ) + $errorItem.ErrorDetails = "No file could be found with the provided path '$_'." + $PSCmdlet.ThrowTerminatingError($errorItem) + } + else { + return $true + } + } + )] + [Alias( 'FullName', 'PSPath' )] + [String] + $Path + ) + + process { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Resolving path $Path" + $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Path) + } +} diff --git a/JiraPS/Public/Add-JiraFilterPermission.ps1 b/JiraPS/Public/Add-JiraFilterPermission.ps1 new file mode 100644 index 00000000..e21bbb6f --- /dev/null +++ b/JiraPS/Public/Add-JiraFilterPermission.ps1 @@ -0,0 +1,81 @@ +function Add-JiraFilterPermission { + [CmdletBinding( SupportsShouldProcess )] + param( + # Filter object to which the permission should be applied + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [PSTypeName('JiraPS.Filter')] + $Filter, + + # Type of the permission to add + [Parameter( Mandatory )] + [ValidateNotNullOrEmpty()] + [ValidateSet('Group', 'Project', 'ProjectRole', 'Authenticated', 'Global')] + [String]$Type, + + # Value for the Type of the permission + # + # The Value differs per Type of the permission. + # Here is a table to know what Value to provide: + # + # |Type |Value |Source | + # |-------------|---------------------|----------------------------------------------------| + # |Group |Name of the Group |Can be retrieved with `(Get-JiraGroup ...).Name` | + # |Project |Id of the Project |Can be retrieved with `(Get-JiraProject ...).Id` | + # |ProjectRole |Id of the ProjectRole|Can be retrieved with `(Get-JiraProjectRole ...).Id`| + # |Authenticated| **must be null** | | + # |Global | **must be null** | | + [String]$Value, + + # Credentials to use to connect to JIRA. + # + # If not specified, this function will use anonymous access. + [PSCredential] + $Credential + ) + + begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + + $resourceURi = "{0}/permission" + } + + process { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + $body = @{ + type = $Type.ToLower() + } + switch ($Type) { + "Group" { + $body["groupname"] = $Value + } + "Project" { + $body["projectId"] = $Value + } + "ProjectRole" { + $body["projectRoleId"] = $Value + } + "Authenticated" { } + "Global" { } + } + + $parameter = @{ + URI = $resourceURi -f $Filter.RestURL + Method = "POST" + Body = ConvertTo-Json $body + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($Filter.Name, "Add Permission [$Type - $Value]")) { + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraFilterPermission -InputObject $result) + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/JiraPS/Public/Get-JiraFilterPermission.ps1 b/JiraPS/Public/Get-JiraFilterPermission.ps1 new file mode 100644 index 00000000..8c3a992a --- /dev/null +++ b/JiraPS/Public/Get-JiraFilterPermission.ps1 @@ -0,0 +1,41 @@ +function Get-JiraFilterPermission { + [CmdletBinding()] + param( + # Filter object from which to retrieve the permissions + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [PSTypeName('JiraPS.Filter')] + $Filter, + + # Credentials to use to connect to JIRA. + # + # If not specified, this function will use anonymous access. + [PSCredential] + $Credential + ) + + begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + + $resourceURi = "{0}/permission" + } + + process { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + $parameter = @{ + URI = $resourceURi -f $Filter.RestURL + Method = "GET" + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraFilterPermission -InputObject $result) + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/JiraPS/Public/Remove-JiraFilterPermission.ps1 b/JiraPS/Public/Remove-JiraFilterPermission.ps1 new file mode 100644 index 00000000..d0313502 --- /dev/null +++ b/JiraPS/Public/Remove-JiraFilterPermission.ps1 @@ -0,0 +1,39 @@ +function Remove-JiraFilterPermission { + [CmdletBinding( SupportsShouldProcess )] + param( + # Filter object to which the permission should be applied + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [PSTypeName('JiraPS.FilterPermission')] + $InputObject, + + # Credentials to use to connect to JIRA. + # + # If not specified, this function will use anonymous access. + [PSCredential] + $Credential + ) + + 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)" + + $parameter = @{ + URI = $InputObject.RestURL + Method = "DELETE" + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($InputObject.Type, "Remove Permission")) { + Invoke-JiraMethod @parameter + } + } + + end { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/docs/en-US/commands/Add-JiraFilterPermission.md b/docs/en-US/commands/Add-JiraFilterPermission.md new file mode 100644 index 00000000..4ef07c0f --- /dev/null +++ b/docs/en-US/commands/Add-JiraFilterPermission.md @@ -0,0 +1,141 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: +schema: 2.0.0 +--- + +# Add-JiraFilterPermission + +## SYNOPSIS +{{Fill in the Synopsis}} + +## SYNTAX + +``` +Add-JiraFilterPermission [-Filter] [-Type] [[-Value] ] [[-Credential] ] + [-WhatIf] [-Confirm] [] +``` + +## DESCRIPTION +{{Fill in the Description}} + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> {{ Add example code here }} +``` + +{{ Add example description here }} + +## PARAMETERS + +### -Confirm +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Credential +{{Fill Credential Description}} + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: 3 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Filter +{{Fill Filter Description}} + +```yaml +Type: Object +Parameter Sets: (All) +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -Type +{{Fill Type Description}} + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: Group, Project, ProjectRole, Authenticated, Global + +Required: True +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Value +{{Fill Value Description}} + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +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 + +### System.Object + + +## OUTPUTS + +### System.Object + +## NOTES + +## RELATED LINKS diff --git a/docs/en-US/commands/Get-JiraFilterPermission.md b/docs/en-US/commands/Get-JiraFilterPermission.md new file mode 100644 index 00000000..98eb689e --- /dev/null +++ b/docs/en-US/commands/Get-JiraFilterPermission.md @@ -0,0 +1,78 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/Get-JiraFilter/ +schema: 2.0.0 +--- + +# Get-JiraFilterPermission + +## SYNOPSIS +{{Fill in the Synopsis}} + +## SYNTAX + +``` +Get-JiraFilterPermission [-Filter] [[-Credential] ] [] +``` + +## DESCRIPTION +{{Fill in the Description}} + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> {{ Add example code here }} +``` + +{{ Add example description here }} + +## PARAMETERS + +### -Credential +{{Fill Credential Description}} + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Filter +{{Fill Filter Description}} + +```yaml +Type: Object +Parameter Sets: (All) +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +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 + +### System.Object + + +## OUTPUTS + +### System.Object + +## NOTES + +## RELATED LINKS diff --git a/docs/en-US/commands/Remove-JiraFilterPermission.md b/docs/en-US/commands/Remove-JiraFilterPermission.md new file mode 100644 index 00000000..aaf802cb --- /dev/null +++ b/docs/en-US/commands/Remove-JiraFilterPermission.md @@ -0,0 +1,110 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: https://atlassianps.org/docs/JiraPS/commands/New-JiraVersion/ +schema: 2.0.0 +--- + +# Remove-JiraFilterPermission + +## SYNOPSIS +{{Fill in the Synopsis}} + +## SYNTAX + +``` +Remove-JiraFilterPermission [-InputObject] [[-Credential] ] [-WhatIf] [-Confirm] + [] +``` + +## DESCRIPTION +{{Fill in the Description}} + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> {{ Add example code here }} +``` + +{{ Add example description here }} + +## PARAMETERS + +### -Confirm +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Credential +{{Fill Credential Description}} + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -InputObject +{{Fill InputObject Description}} + +```yaml +Type: Object +Parameter Sets: (All) +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -WhatIf +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +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 + +### System.Object + + +## OUTPUTS + +### System.Object + +## NOTES + +## RELATED LINKS From 3d4c18138a37af31d4e0ad5f6edd50e41ca50cde Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 28 May 2018 14:39:55 +0200 Subject: [PATCH 12/83] Added parameter to influence max# of users to search --- JiraPS/Public/Get-JiraUser.ps1 | 22 ++++++++++++++--- Tests/Get-JiraUser.Tests.ps1 | 24 ++++++++++++++++++ docs/en-US/commands/Get-JiraUser.md | 38 ++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/JiraPS/Public/Get-JiraUser.ps1 b/JiraPS/Public/Get-JiraUser.ps1 index 51537075..0df2308b 100644 --- a/JiraPS/Public/Get-JiraUser.ps1 +++ b/JiraPS/Public/Get-JiraUser.ps1 @@ -13,10 +13,18 @@ function Get-JiraUser { [Switch] $IncludeInactive, - [Parameter()] - [System.Management.Automation.PSCredential] - [System.Management.Automation.Credential()] - $Credential = [System.Management.Automation.PSCredential]::Empty + [Parameter( ParameterSetName = 'ByUserName' )] + [ValidateRange(1, 1000)] + [UInt32] + $MaxResults = 50, + + [Parameter( ParameterSetName = 'ByUserName' )] + [ValidateNotNullOrEmpty()] + [UInt64] + $Skip = 0, + + [PSCredential] + $Credential ) begin { @@ -30,6 +38,12 @@ function Get-JiraUser { if ($IncludeInactive) { $searchResourceUri += "&includeInactive=true" } + if ($MaxResults) { + $searchResourceUri += "&maxResults=$MaxResults" + } + if ($Skip) { + $searchResourceUri += "&startAt=$Skip" + } } process { diff --git a/Tests/Get-JiraUser.Tests.ps1 b/Tests/Get-JiraUser.Tests.ps1 index 2128e992..06a156b9 100644 --- a/Tests/Get-JiraUser.Tests.ps1 +++ b/Tests/Get-JiraUser.Tests.ps1 @@ -128,6 +128,30 @@ Describe "Get-JiraUser" { Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly 2 -Scope It -ParameterFilter {$URI -like "$jiraServer/rest/api/*/user?username=$testUsername&expand=groups"} } + It "Allow it search for multiple users" { + Get-JiraUser -UserName "%" + + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly 1 -Scope It -ParameterFilter { + $URI -like "$jiraServer/rest/api/*/user/search?*username=%25*" + } + } + + It "Allows to change the max number of users to be returned" { + Get-JiraUser -UserName "%" -MaxResults 100 + + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly 1 -Scope It -ParameterFilter { + $URI -like "$jiraServer/rest/api/*/user/search?*maxResults=100*" + } + } + + It "Can skip a certain amount of results" { + Get-JiraUser -UserName "%" -Skip 10 + + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly 1 -Scope It -ParameterFilter { + $URI -like "$jiraServer/rest/api/*/user/search?*startAt=10*" + } + } + It "Provides information about the user's group membership in Jira" { $getResult = Get-JiraUser -UserName $testUsername diff --git a/docs/en-US/commands/Get-JiraUser.md b/docs/en-US/commands/Get-JiraUser.md index 7c04aa99..50789b0f 100644 --- a/docs/en-US/commands/Get-JiraUser.md +++ b/docs/en-US/commands/Get-JiraUser.md @@ -24,7 +24,7 @@ Get-JiraUser [-Credential ] [] ### ByUserName ```powershell -Get-JiraUser [-UserName] [-IncludeInactive] [-Credential ] [] +Get-JiraUser [-UserName] [-IncludeInactive] [[-MaxResults] ] [-Credential ] [] ``` ### ByInputObject @@ -113,6 +113,42 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -MaxResults + +Maximum number of user to be returned. + +> The API does not allow for any value higher than 1000. + +```yaml +Type: UInt32 +Parameter Sets: ByUserName +Aliases: + +Required: False +Position: Named +Default value: 50 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Skip + +Controls how many objects will be skipped before starting output. + +Defaults to 0. + +```yaml +Type: UInt64 +Parameter Sets: ByUserName +Aliases: + +Required: False +Position: Named +Default value: 0 +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Credential Credentials to use to connect to JIRA. From eb3314c32a6bed7fe03f4d5fbe3c7e8bc2f01777 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 28 May 2018 21:01:20 +0200 Subject: [PATCH 13/83] Fixed Credential pop up --- JiraPS/Private/Invoke-WebRequest.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/JiraPS/Private/Invoke-WebRequest.ps1 b/JiraPS/Private/Invoke-WebRequest.ps1 index be45751c..9393d2f9 100644 --- a/JiraPS/Private/Invoke-WebRequest.ps1 +++ b/JiraPS/Private/Invoke-WebRequest.ps1 @@ -30,7 +30,7 @@ function Invoke-WebRequest { [pscredential] [System.Management.Automation.CredentialAttribute()] - ${Credential}, + ${Credential} = [System.Management.Automation.PSCredential]::Empty, [switch] ${UseDefaultCredentials}, @@ -68,7 +68,7 @@ function Invoke-WebRequest { [pscredential] [System.Management.Automation.CredentialAttribute()] - ${ProxyCredential}, + ${ProxyCredential} = [System.Management.Automation.PSCredential]::Empty, [switch] ${ProxyUseDefaultCredentials}, @@ -94,7 +94,7 @@ function Invoke-WebRequest { ${PassThru}) begin { - if ($Credential) { + if ($Credential -and ($Credential -ne [System.Management.Automation.PSCredential]::Empty)) { $SecureCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes( $('{0}:{1}' -f $Credential.UserName, $Credential.GetNetworkCredential().Password) )) From 6ba039f2d058257d08880059b3af5ccfbfd31fa9 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 29 May 2018 09:06:25 +0200 Subject: [PATCH 14/83] Fixed Documentation and Test --- JiraPS/Public/Get-JiraUser.ps1 | 6 ++++-- Tests/Get-JiraUser.Tests.ps1 | 6 +++++- docs/en-US/commands/Get-JiraUser.md | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/JiraPS/Public/Get-JiraUser.ps1 b/JiraPS/Public/Get-JiraUser.ps1 index 0df2308b..bb88c2ea 100644 --- a/JiraPS/Public/Get-JiraUser.ps1 +++ b/JiraPS/Public/Get-JiraUser.ps1 @@ -23,8 +23,10 @@ function Get-JiraUser { [UInt64] $Skip = 0, - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { diff --git a/Tests/Get-JiraUser.Tests.ps1 b/Tests/Get-JiraUser.Tests.ps1 index 06a156b9..203ea66a 100644 --- a/Tests/Get-JiraUser.Tests.ps1 +++ b/Tests/Get-JiraUser.Tests.ps1 @@ -68,7 +68,11 @@ Describe "Get-JiraUser" { } # Searching for a user. - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/user/search?username=$testUsername"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/user/search?*username=$testUsername*"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + ConvertFrom-Json -InputObject $restResult + } + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/user/search?*username=%25*"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json -InputObject $restResult } diff --git a/docs/en-US/commands/Get-JiraUser.md b/docs/en-US/commands/Get-JiraUser.md index 50789b0f..76d9d06c 100644 --- a/docs/en-US/commands/Get-JiraUser.md +++ b/docs/en-US/commands/Get-JiraUser.md @@ -24,7 +24,7 @@ Get-JiraUser [-Credential ] [] ### ByUserName ```powershell -Get-JiraUser [-UserName] [-IncludeInactive] [[-MaxResults] ] [-Credential ] [] +Get-JiraUser [-UserName] [-IncludeInactive] [[-MaxResults] ] [[-Skip] ] [-Credential ] [] ``` ### ByInputObject From f1a6daaa94aa0aa1b551f9cbc296e00521edf370 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 29 May 2018 20:38:58 +0200 Subject: [PATCH 15/83] Fixed header entry which is no supported in PSv3 --- JiraPS/Public/Invoke-JiraMethod.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index d3a0123c..4312fa0f 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -44,9 +44,13 @@ function Invoke-JiraMethod { # pass input to local variable # this allows to use the PSBoundParameters for recursion $_headers = @{ # Set any default headers - "Accept" = "application/json" + # "Accept" = "application/json" "Accept-Charset" = "utf-8" } + # Bug in PSv3's .Net API + if ($PSVersionTable.PSVersion.Major -eq 3) { + $_headers["Accept"] = "application/json" + } foreach ($item in $Headers.Key) { $_headers[$item] = $Headers[$item] } } From 803e0d8dcbd81d784fb8a16afe0197a13480f4f6 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 29 May 2018 21:42:02 +0200 Subject: [PATCH 16/83] Updated constructor of exceptions to be PSv3 compliant --- JiraPS/JiraPS.psm1 | 14 ++--- JiraPS/Private/Resolve-JiraError.ps1 | 22 ++++---- JiraPS/Private/Resolve-JiraIssueObject.ps1 | 11 ++-- JiraPS/Public/Add-JiraIssueAttachment.ps1 | 33 +++++------ JiraPS/Public/Add-JiraIssueComment.ps1 | 11 ++-- JiraPS/Public/Add-JiraIssueLink.ps1 | 22 ++++---- JiraPS/Public/Add-JiraIssueWatcher.ps1 | 11 ++-- JiraPS/Public/Add-JiraIssueWorklog.ps1 | 11 ++-- JiraPS/Public/Get-JiraComponent.ps1 | 11 ++-- JiraPS/Public/Get-JiraConfigServer.ps1 | 33 +++++------ JiraPS/Public/Get-JiraFilter.ps1 | 11 ++-- JiraPS/Public/Get-JiraGroupMember.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssue.ps1 | 22 ++++---- JiraPS/Public/Get-JiraIssueAttachment.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssueComment.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssueEditMetadata.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssueLink.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssueLinkType.ps1 | 11 ++-- JiraPS/Public/Get-JiraIssueWatcher.ps1 | 11 ++-- JiraPS/Public/Get-JiraRemoteLink.ps1 | 11 ++-- JiraPS/Public/Invoke-JiraIssueTransition.ps1 | 55 +++++++++---------- JiraPS/Public/New-JiraIssue.ps1 | 22 ++++---- JiraPS/Public/New-JiraVersion.ps1 | 22 ++++---- JiraPS/Public/Remove-JiraGroup.ps1 | 11 ++-- JiraPS/Public/Remove-JiraGroupMember.ps1 | 22 ++++---- JiraPS/Public/Remove-JiraIssueAttachment.ps1 | 22 ++++---- JiraPS/Public/Remove-JiraIssueLink.ps1 | 11 ++-- JiraPS/Public/Remove-JiraIssueWatcher.ps1 | 11 ++-- JiraPS/Public/Remove-JiraRemoteLink.ps1 | 11 ++-- JiraPS/Public/Remove-JiraUser.ps1 | 11 ++-- JiraPS/Public/Remove-JiraVersion.ps1 | 11 ++-- JiraPS/Public/Set-JiraConfigServer.ps1 | 11 ++-- JiraPS/Public/Set-JiraIssue.ps1 | 22 ++++---- JiraPS/Public/Set-JiraIssueLabel.ps1 | 11 ++-- JiraPS/Public/Set-JiraUser.ps1 | 22 ++++---- JiraPS/Public/Set-JiraVersion.ps1 | 22 ++++---- 37 files changed, 277 insertions(+), 331 deletions(-) diff --git a/JiraPS/JiraPS.psm1 b/JiraPS/JiraPS.psm1 index 383636c1..c4cac996 100644 --- a/JiraPS/JiraPS.psm1 +++ b/JiraPS/JiraPS.psm1 @@ -24,14 +24,14 @@ foreach ($file in @($PublicFunctions + $PrivateFunctions)) { . $file.FullName } catch { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Function not found"), - 'Load.Function', - [System.Management.Automation.ErrorCategory]::ObjectNotFound, - $file - ) + $exception = ([System.ArgumentException]"Function not found") + $errorId = "Load.Function" + $errorCategory = 'ObjectNotFound' + $errorTarget = $file + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Failed to import function $($file.BaseName)" - throw $errorItem + # throw $errorItem + throw $_ } } Export-ModuleMember -Function $PublicFunctions.BaseName diff --git a/JiraPS/Private/Resolve-JiraError.ps1 b/JiraPS/Private/Resolve-JiraError.ps1 index a13111b3..b87bfda2 100644 --- a/JiraPS/Private/Resolve-JiraError.ps1 +++ b/JiraPS/Private/Resolve-JiraError.ps1 @@ -21,12 +21,11 @@ if ($i.errorMessages) { foreach ($e in $i.errorMessages) { if ($WriteError) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Server responded with Error"), - "ServerResponse", - [System.Management.Automation.ErrorCategory]::NotSpecified, - $i - ) + $exception = ([System.ArgumentException]"Server responded with Error") + $errorId = "ServerResponse" + $errorCategory = 'NotSpecified' + $errorTarget = $i + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Jira encountered an error: [$e]" $Cmdlet.WriteError($errorItem) } @@ -48,12 +47,11 @@ $keys = (Get-Member -InputObject $i.errors | Where-Object -FilterScript {$_.MemberType -eq 'NoteProperty'}).Name foreach ($k in $keys) { if ($WriteError) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Server responded with Error"), - "ServerResponse.$k", - [System.Management.Automation.ErrorCategory]::NotSpecified, - $i - ) + $exception = ([System.ArgumentException]"Server responded with Error") + $errorId = "ServerResponse.$k" + $errorCategory = 'NotSpecified' + $errorTarget = $i + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Jira encountered an error: [$k] - $($i.errors.$k)" $Cmdlet.WriteError($errorItem) } diff --git a/JiraPS/Private/Resolve-JiraIssueObject.ps1 b/JiraPS/Private/Resolve-JiraIssueObject.ps1 index 3277c889..12afb5d3 100644 --- a/JiraPS/Private/Resolve-JiraIssueObject.ps1 +++ b/JiraPS/Private/Resolve-JiraIssueObject.ps1 @@ -10,12 +10,11 @@ function Resolve-JiraIssueObject { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) } diff --git a/JiraPS/Public/Add-JiraIssueAttachment.ps1 b/JiraPS/Public/Add-JiraIssueAttachment.ps1 index 1c098d50..a298b39f 100644 --- a/JiraPS/Public/Add-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Add-JiraIssueAttachment.ps1 @@ -6,12 +6,11 @@ function Add-JiraIssueAttachment { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# @@ -36,12 +35,11 @@ function Add-JiraIssueAttachment { [ValidateScript( { if (-not (Test-Path $_ -PathType Leaf)) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"File not found"), - 'ParameterValue.FileNotFound', - [System.Management.Automation.ErrorCategory]::ObjectNotFound, - $_ - ) + $exception = ([System.ArgumentException]"File not found") #fix code highlighting] + $errorId = 'ParameterValue.FileNotFound' + $errorCategory = 'ObjectNotFound' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "No file could be found with the provided path '$_'." $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -74,12 +72,11 @@ function Add-JiraIssueAttachment { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" if (@($Issue).Count -ne 1) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"invalid Issue provided"), - 'ParameterValue.JiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"invalid Issue provided") + $errorId = 'ParameterValue.JiraIssue' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Only one Issue can be provided at a time." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/Add-JiraIssueComment.ps1 b/JiraPS/Public/Add-JiraIssueComment.ps1 index 651d0881..50032816 100644 --- a/JiraPS/Public/Add-JiraIssueComment.ps1 +++ b/JiraPS/Public/Add-JiraIssueComment.ps1 @@ -11,12 +11,11 @@ function Add-JiraIssueComment { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Add-JiraIssueLink.ps1 b/JiraPS/Public/Add-JiraIssueLink.ps1 index f8a2f867..c5770ef9 100644 --- a/JiraPS/Public/Add-JiraIssueLink.ps1 +++ b/JiraPS/Public/Add-JiraIssueLink.ps1 @@ -6,12 +6,11 @@ function Add-JiraIssueLink { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# @@ -36,12 +35,11 @@ function Add-JiraIssueLink { ($objectProperties.Name -contains "type") -and (($objectProperties.Name -contains "outwardIssue") -or ($objectProperties.Name -contains "inwardIssue")) )) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Parameter"), - 'ParameterProperties.Incomplete', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Parameter") #fix code highlighting] + $errorId = 'ParameterProperties.Incomplete' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "The IssueLink provided does not contain the information needed." $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Add-JiraIssueWatcher.ps1 b/JiraPS/Public/Add-JiraIssueWatcher.ps1 index ac9282ea..323eb526 100644 --- a/JiraPS/Public/Add-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Add-JiraIssueWatcher.ps1 @@ -14,12 +14,11 @@ [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Add-JiraIssueWorklog.ps1 b/JiraPS/Public/Add-JiraIssueWorklog.ps1 index 7c164be3..c8ee9b28 100644 --- a/JiraPS/Public/Add-JiraIssueWorklog.ps1 +++ b/JiraPS/Public/Add-JiraIssueWorklog.ps1 @@ -11,12 +11,11 @@ function Add-JiraIssueWorklog { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Get-JiraComponent.ps1 b/JiraPS/Public/Get-JiraComponent.ps1 index 2ad92467..7b58099a 100644 --- a/JiraPS/Public/Get-JiraComponent.ps1 +++ b/JiraPS/Public/Get-JiraComponent.ps1 @@ -6,12 +6,11 @@ function Get-JiraComponent { [ValidateScript( { if (("JiraPS.Project" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraProject', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraProject' + $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.Project] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Get-JiraConfigServer.ps1 b/JiraPS/Public/Get-JiraConfigServer.ps1 index 63caef8d..297a114f 100644 --- a/JiraPS/Public/Get-JiraConfigServer.ps1 +++ b/JiraPS/Public/Get-JiraConfigServer.ps1 @@ -26,12 +26,11 @@ function Get-JiraConfigServer { } if (-not (Test-Path -Path $ConfigFile)) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.IO.FileNotFoundException]"Could not find $ConfigFile"), - 'ConfigFile.NotFound', - [System.Management.Automation.ErrorCategory]::ObjectNotFound, - $ConfigFile - ) + $exception = ([System.IO.FileNotFoundException]"Could not find $ConfigFile") + $errorId = 'ConfigFile.NotFound' + $errorCategory = 'ObjectNotFound' + $errorTarget = $ConfigFile + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Config file [$ConfigFile] does not exist. Use Set-JiraConfigServer first to define the configuration file." $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -41,12 +40,11 @@ function Get-JiraConfigServer { $xmlConfig = $xml.DocumentElement if ($xmlConfig.LocalName -ne 'Config') { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.IO.FileFormatException]"XML had not the expected format"), - 'ConfigFile.UnexpectedElement', - [System.Management.Automation.ErrorCategory]::ParserError, - $ConfigFile - ) + $exception = ([System.IO.FileFormatException]"XML had not the expected format") + $errorId = 'ConfigFile.UnexpectedElement' + $errorCategory = ParserError + $errorTarget = $ConfigFile + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Unexpected document element [$($xmlConfig.LocalName)] in configuration file [$ConfigFile]. You may need to delete the config file and recreate it using Set-JiraConfigServer." $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -55,12 +53,11 @@ function Get-JiraConfigServer { Write-Output $xmlConfig.Server } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.UriFormatException]"Could not find URI"), - 'ConfigFile.EmptyElement', - [System.Management.Automation.ErrorCategory]::OpenError, - $ConfigFile - ) + $exception = ([System.UriFormatException]"Could not find URI") + $errorId = 'ConfigFile.EmptyElement' + $errorCategory = OpenError + $errorTarget = $ConfigFile + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "No Server element is defined in the config file. Use Set-JiraConfigServer to define one." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/Get-JiraFilter.ps1 b/JiraPS/Public/Get-JiraFilter.ps1 index 4d1b25de..2a7789b4 100644 --- a/JiraPS/Public/Get-JiraFilter.ps1 +++ b/JiraPS/Public/Get-JiraFilter.ps1 @@ -16,12 +16,11 @@ [ValidateScript( { if (("JiraPS.Filter" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraFilter', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Get-JiraGroupMember.ps1 b/JiraPS/Public/Get-JiraGroupMember.ps1 index d204889a..8d1d7a7f 100644 --- a/JiraPS/Public/Get-JiraGroupMember.ps1 +++ b/JiraPS/Public/Get-JiraGroupMember.ps1 @@ -6,12 +6,11 @@ function Get-JiraGroupMember { [ValidateScript( { if (("JiraPS.Group" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraGroup', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraGroup' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Group. Expected [JiraPS.Group] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 62ffc564..7bcd3c0b 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -12,12 +12,11 @@ function Get-JiraIssue { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) } @@ -45,12 +44,11 @@ function Get-JiraIssue { [ValidateScript( { if (("JiraPS.Filter" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraFilter', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Get-JiraIssueAttachment.ps1 b/JiraPS/Public/Get-JiraIssueAttachment.ps1 index d093f11d..b766a7d9 100644 --- a/JiraPS/Public/Get-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Get-JiraIssueAttachment.ps1 @@ -6,12 +6,11 @@ function Get-JiraIssueAttachment { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraIssue' + $errorCategory = [System.Management.Automation.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) <# diff --git a/JiraPS/Public/Get-JiraIssueComment.ps1 b/JiraPS/Public/Get-JiraIssueComment.ps1 index b61b3824..34e74445 100644 --- a/JiraPS/Public/Get-JiraIssueComment.ps1 +++ b/JiraPS/Public/Get-JiraIssueComment.ps1 @@ -6,12 +6,11 @@ function Get-JiraIssueComment { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 b/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 index d0241adb..38bd086e 100644 --- a/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 +++ b/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 @@ -76,12 +76,11 @@ function Get-JiraIssueCreateMetadata { Write-Output (ConvertTo-JiraCreateMetaField -InputObject $result) } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"No results"), - 'IssueMetadata.ObjectNotFound', - [System.Management.Automation.ErrorCategory]::ObjectNotFound, - $Project - ) + $exception = ([System.ArgumentException]"No results") + $errorId = 'IssueMetadata.ObjectNotFound' + $errorCategory = 'ObjectNotFound' + $errorTarget = $Project + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "No metadata found for project $Project and issueType $IssueType." Throw $errorItem } diff --git a/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 b/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 index 2013156d..7bbfac7a 100644 --- a/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 +++ b/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 @@ -79,12 +79,11 @@ function Get-JiraIssueEditMetadata { Write-Output (ConvertTo-JiraEditMetaField -InputObject $result) } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"No results"), - 'IssueMetadata.ObjectNotFound', - [System.Management.Automation.ErrorCategory]::ObjectNotFound, - $Project - ) + $exception = ([System.ArgumentException]"No results") + $errorId = 'IssueMetadata.ObjectNotFound' + $errorCategory = 'ObjectNotFound' + $errorTarget = $Project + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "No metadata found for project $Project and issueType $IssueType." Throw $errorItem } diff --git a/JiraPS/Public/Get-JiraIssueLink.ps1 b/JiraPS/Public/Get-JiraIssueLink.ps1 index 99b00204..dbe9eb5c 100644 --- a/JiraPS/Public/Get-JiraIssueLink.ps1 +++ b/JiraPS/Public/Get-JiraIssueLink.ps1 @@ -25,12 +25,11 @@ function Get-JiraIssueLink { # Validate input object from Pipeline if (($_) -and ("JiraPS.IssueLink" -notin $_.PSObject.TypeNames)) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Parameter"), - 'ParameterProperties.WrongObjectType', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Id - ) + $exception = ([System.ArgumentException]"Invalid Parameter") + $errorId = 'ParameterProperties.WrongObjectType' + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument + $errorTarget = $Id + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "The IssueLink provided did not match the constraints." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/Get-JiraIssueLinkType.ps1 b/JiraPS/Public/Get-JiraIssueLinkType.ps1 index 0496b427..c6205061 100644 --- a/JiraPS/Public/Get-JiraIssueLinkType.ps1 +++ b/JiraPS/Public/Get-JiraIssueLinkType.ps1 @@ -6,12 +6,11 @@ function Get-JiraIssueLinkType { [ValidateScript( { if (("JiraPS.IssueLinkType" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String])) -and (($_ -isnot [Int]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssueLinkType', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraIssueLinkType' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for IssueLinkType. Expected [JiraPS.IssueLinkType], [String] or [Int], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Get-JiraIssueWatcher.ps1 b/JiraPS/Public/Get-JiraIssueWatcher.ps1 index fdd9294c..d8ca1ab4 100644 --- a/JiraPS/Public/Get-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Get-JiraIssueWatcher.ps1 @@ -6,12 +6,11 @@ [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlight] + $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) <# diff --git a/JiraPS/Public/Get-JiraRemoteLink.ps1 b/JiraPS/Public/Get-JiraRemoteLink.ps1 index daf3d3fc..9761cd95 100644 --- a/JiraPS/Public/Get-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Get-JiraRemoteLink.ps1 @@ -6,12 +6,11 @@ function Get-JiraRemoteLink { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Invoke-JiraIssueTransition.ps1 b/JiraPS/Public/Invoke-JiraIssueTransition.ps1 index 34800310..3b7db630 100644 --- a/JiraPS/Public/Invoke-JiraIssueTransition.ps1 +++ b/JiraPS/Public/Invoke-JiraIssueTransition.ps1 @@ -6,12 +6,11 @@ function Invoke-JiraIssueTransition { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# @@ -71,12 +70,11 @@ function Invoke-JiraIssueTransition { $transitionId = [Int]"$Transition" } catch { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraTransition', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Transition - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") + $errorId = 'ParameterType.NotJiraTransition' + $errorCategory = 'InvalidArgumenty' + $errorTarget = $Transition + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTargetError $errorItem.ErrorDetails = "Wrong object type provided for Transition. Expected [JiraPS.Transition] or [Int], but was $($Transition.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -84,12 +82,11 @@ function Invoke-JiraIssueTransition { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Checking that the issue can perform the given transition" if (($issueObj.Transition.Id) -notcontains $transitionId) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid value for Parameter"), - 'ParameterValue.InvalidTransition', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Issue - ) + $exception = ([System.ArgumentException]"Invalid value for Parameter") + $errorId = 'ParameterValue.InvalidTransition' + $errorCategory = 'InvalidArgument' + $errorTarget = $Issue + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "The specified Jira issue cannot perform transition [$transitionId]. Check the issue's Transition property and provide a transition valid for its current state." $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -117,12 +114,11 @@ function Invoke-JiraIssueTransition { $validAssignee = $true } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid value for Parameter"), - 'ParameterValue.InvalidAssignee', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Assignee - ) + $exception = ([System.ArgumentException]"Invalid value for Parameter") + $errorId = 'ParameterValue.InvalidAssignee' + $errorCategory = 'InvalidArgument' + $errorTarget = $Assignee + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Unable to validate Jira user [$Assignee]. Use Get-JiraUser for more details." $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -162,12 +158,11 @@ function Invoke-JiraIssueTransition { }) } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid value for Parameter"), - 'ParameterValue.InvalidFields', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Fields - ) + $exception = ([System.ArgumentException]"Invalid value for Parameter") + $errorId = 'ParameterValue.InvalidFields' + $errorCategory = 'InvalidArgument' + $errorTarget = $Fields + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/New-JiraIssue.ps1 b/JiraPS/Public/New-JiraIssue.ps1 index 57eae3b9..ab8917f1 100644 --- a/JiraPS/Public/New-JiraIssue.ps1 +++ b/JiraPS/Public/New-JiraIssue.ps1 @@ -109,12 +109,11 @@ function New-JiraIssue { $requestBody["$id"] = $value } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid value for Parameter"), - 'ParameterValue.InvalidFields', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Fields - ) + $exception = ([System.ArgumentException]"Invalid value for Parameter") + $errorId = 'ParameterValue.InvalidFields' + $errorCategory = 'InvalidArgument' + $errorTarget = $Fields + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Unable to identify field [$name] from -Fields hashtable. Use Get-JiraField for more information." $PSCmdlet.ThrowTerminatingError($errorItem) } @@ -128,12 +127,11 @@ function New-JiraIssue { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Required field (id=[$($c.Id)], name=[$($c.Name)]) was provided (value=[$($requestBody.$($c.Id))])" } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid or missing value Parameter"), - 'ParameterValue.CreateMetaFailure', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Fields - ) + $exception = ([System.ArgumentException]"Invalid or missing value Parameter") + $errorId = 'ParameterValue.CreateMetaFailure' + $errorCategory = 'InvalidArgument' + $errorTarget = $Fields + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Jira's metadata for project [$Project] and issue type [$IssueType] specifies that a field is required that was not provided (name=[$($c.Name)], id=[$($c.Id)]). Use Get-JiraIssueCreateMetadata for more information." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/New-JiraVersion.ps1 b/JiraPS/Public/New-JiraVersion.ps1 index 2fceb764..7d6b19c2 100644 --- a/JiraPS/Public/New-JiraVersion.ps1 +++ b/JiraPS/Public/New-JiraVersion.ps1 @@ -6,12 +6,11 @@ [ValidateScript( { if (("JiraPS.Version" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraVersion', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraVersion' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Version. Expected [JiraPS.Version] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# @@ -41,12 +40,11 @@ {"JiraPS.Project" -in $Input.PSObject.TypeNames} { return $true } {$Input -is [String]} { return $true} Default { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraProject', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Input - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraProject' + $errorCategory = 'InvalidArgument' + $errorTarget = $Input + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Project. Expected [JiraPS.Project] or [String], but was $($Input.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Remove-JiraGroup.ps1 b/JiraPS/Public/Remove-JiraGroup.ps1 index 5616c8a8..d4744652 100644 --- a/JiraPS/Public/Remove-JiraGroup.ps1 +++ b/JiraPS/Public/Remove-JiraGroup.ps1 @@ -6,12 +6,11 @@ [ValidateScript( { if (("JiraPS.Group" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraGroup', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraGroup' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Group. Expected [JiraPS.Group] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Remove-JiraGroupMember.ps1 b/JiraPS/Public/Remove-JiraGroupMember.ps1 index 0adaea50..9a6c22fa 100644 --- a/JiraPS/Public/Remove-JiraGroupMember.ps1 +++ b/JiraPS/Public/Remove-JiraGroupMember.ps1 @@ -6,12 +6,11 @@ function Remove-JiraGroupMember { [ValidateScript( { if (("JiraPS.Group" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraGroup', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraGroup' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Group. Expected [JiraPS.Group] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# @@ -33,12 +32,11 @@ function Remove-JiraGroupMember { [ValidateScript( { if (("JiraPS.User" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.UotJirauser', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.UotJirauser' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for User. Expected [JiraPS.User] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Remove-JiraIssueAttachment.ps1 b/JiraPS/Public/Remove-JiraIssueAttachment.ps1 index 873c2b57..3586f94b 100644 --- a/JiraPS/Public/Remove-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Remove-JiraIssueAttachment.ps1 @@ -12,12 +12,11 @@ function Remove-JiraIssueAttachment { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# @@ -87,12 +86,11 @@ function Remove-JiraIssueAttachment { Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$Issue [$Issue]" if (@($Issue).Count -ne 1) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"invalid Issue provided"), - 'ParameterValue.JiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"invalid Issue provided") + $errorId = 'ParameterValue.JiraIssue' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Only one Issue can be provided at a time." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/Remove-JiraIssueLink.ps1 b/JiraPS/Public/Remove-JiraIssueLink.ps1 index 8b9db97f..17921300 100644 --- a/JiraPS/Public/Remove-JiraIssueLink.ps1 +++ b/JiraPS/Public/Remove-JiraIssueLink.ps1 @@ -11,12 +11,11 @@ function Remove-JiraIssueLink { {("JiraPS.Issue" -in $Input.PSObject.TypeNames) -and ("issueLinks" -in $objectProperties.Name)} { return $true } {("JiraPS.IssueLink" -in $Input.PSObject.TypeNames) -and ("Id" -in $objectProperties.Name)} { return $true } default { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Input - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraIssue' + $errorCategory = 'InvalidArgument' + $errorTarget = $Input + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Issue. Expected [JiraPS.Issue], [JiraPS.IssueLink] or [String], but was $($Input.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Remove-JiraIssueWatcher.ps1 b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 index cdd8492f..18ea4798 100644 --- a/JiraPS/Public/Remove-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 @@ -10,12 +10,11 @@ [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Remove-JiraRemoteLink.ps1 b/JiraPS/Public/Remove-JiraRemoteLink.ps1 index d773affe..59de01a8 100644 --- a/JiraPS/Public/Remove-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Remove-JiraRemoteLink.ps1 @@ -6,12 +6,11 @@ function Remove-JiraRemoteLink { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Remove-JiraUser.ps1 b/JiraPS/Public/Remove-JiraUser.ps1 index 2ad6533c..121c956f 100644 --- a/JiraPS/Public/Remove-JiraUser.ps1 +++ b/JiraPS/Public/Remove-JiraUser.ps1 @@ -6,12 +6,11 @@ function Remove-JiraUser { [ValidateScript( { if (("JiraPS.User" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraUser', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraUser' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for User. Expected [JiraPS.User] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Remove-JiraVersion.ps1 b/JiraPS/Public/Remove-JiraVersion.ps1 index 3b20dc14..fac3aaf8 100644 --- a/JiraPS/Public/Remove-JiraVersion.ps1 +++ b/JiraPS/Public/Remove-JiraVersion.ps1 @@ -6,12 +6,11 @@ [ValidateScript( { if (("JiraPS.Version" -notin $_.PSObject.TypeNames) -and (($_ -isnot [Int]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraVersion', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraVersion' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Version. Expected [JiraPS.Version] or [Int], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# diff --git a/JiraPS/Public/Set-JiraConfigServer.ps1 b/JiraPS/Public/Set-JiraConfigServer.ps1 index 7fad90cf..a95d7ebb 100644 --- a/JiraPS/Public/Set-JiraConfigServer.ps1 +++ b/JiraPS/Public/Set-JiraConfigServer.ps1 @@ -44,12 +44,11 @@ function Set-JiraConfigServer { $xmlConfig = $xml.DocumentElement if ($xmlConfig.LocalName -ne 'Config') { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Document"), - 'InvalidObject.InvalidDocument', - [System.Management.Automation.ErrorCategory]::InvalidData, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Document") + $errorId = 'InvalidObject.InvalidDocument' + $errorCategory = 'InvalidData' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Unexpected document element [$($xmlConfig.LocalName)] in configuration file. You may need to delete the config file and recreate it using this function." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 81c03511..337c0132 100644 --- a/JiraPS/Public/Set-JiraIssue.ps1 +++ b/JiraPS/Public/Set-JiraIssue.ps1 @@ -6,12 +6,11 @@ function Set-JiraIssue { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# @@ -90,12 +89,11 @@ function Set-JiraIssue { $validAssignee = $true } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid value for Parameter"), - 'ParameterValue.InvalidAssignee', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Assignee - ) + $exception = ([System.ArgumentException]"Invalid value for Parameter") + $errorId = 'ParameterValue.InvalidAssignee' + $errorCategory = 'InvalidArgument' + $errorTarget = $Assignee + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Unable to validate Jira user [$Assignee]. Use Get-JiraUser for more details." $PSCmdlet.ThrowTerminatingError($errorItem) } diff --git a/JiraPS/Public/Set-JiraIssueLabel.ps1 b/JiraPS/Public/Set-JiraIssueLabel.ps1 index 11b8a7b4..8fde41fa 100644 --- a/JiraPS/Public/Set-JiraIssueLabel.ps1 +++ b/JiraPS/Public/Set-JiraIssueLabel.ps1 @@ -6,12 +6,11 @@ [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $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) <# diff --git a/JiraPS/Public/Set-JiraUser.ps1 b/JiraPS/Public/Set-JiraUser.ps1 index 69029ff4..93ef46ff 100644 --- a/JiraPS/Public/Set-JiraUser.ps1 +++ b/JiraPS/Public/Set-JiraUser.ps1 @@ -6,12 +6,11 @@ function Set-JiraUser { [ValidateScript( { if (("JiraPS.User" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraUser', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraUser' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for User. Expected [JiraPS.User] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# @@ -41,12 +40,11 @@ function Set-JiraUser { return $true } else { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Argument"), - 'ParameterValue.NotEmail', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $Issue - ) + $exception = ([System.ArgumentException]"Invalid Argument") #fix code highlighting] + $errorId = 'ParameterValue.NotEmail' + $errorCategory = 'InvalidArgument' + $errorTarget = $Issue + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "The value provided does not look like an email address." $PSCmdlet.ThrowTerminatingError($errorItem) return $false diff --git a/JiraPS/Public/Set-JiraVersion.ps1 b/JiraPS/Public/Set-JiraVersion.ps1 index 4c74e244..3a96f82d 100644 --- a/JiraPS/Public/Set-JiraVersion.ps1 +++ b/JiraPS/Public/Set-JiraVersion.ps1 @@ -6,12 +6,11 @@ [ValidateScript( { if (("JiraPS.Version" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraVersion', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraVersion' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Version. Expected [JiraPS.Version] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# @@ -48,12 +47,11 @@ [ValidateScript( { if (("JiraPS.Project" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraProject', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraProject' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Project. Expected [JiraPS.Project] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# From 0d2bbc1b0e78048bc83b22efab4350c705463eba Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Fri, 25 May 2018 14:56:55 -0700 Subject: [PATCH 17/83] Initial implementation of Remove-JiraIssue w/ documentation --- JiraPS/Public/Remove-JiraIssue.ps1 | 98 +++++++++++++ docs/en-US/commands/Remove-JiraIssue.md | 181 ++++++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 JiraPS/Public/Remove-JiraIssue.ps1 create mode 100644 docs/en-US/commands/Remove-JiraIssue.md diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 new file mode 100644 index 00000000..35fdfaa6 --- /dev/null +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -0,0 +1,98 @@ +function Remove-JiraIssue { + [CmdletBinding( + ConfirmImpact = 'High', + SupportsShouldProcess + )] + param ( + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [ValidateScript( + { + if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { + $errorItem = [System.Management.Automation.ErrorRecord]::new( + ([System.ArgumentException]"Invalid Type for Parameter"), + 'ParameterType.NotJiraIssue', + [System.Management.Automation.ErrorCategory]::InvalidArgument, + $_ + ) + $errorItem.ErrorDetails = "Wrong object type provided for Issue. Expected [JiraPS.Issue] 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[]] + $Issue, + + [Switch] + $IncludeSubTasks, + + [PSCredential] + $Credential, + + [Switch] + $Force + ) + + begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + + $server = Get-JiraConfigServer -ErrorAction Stop + + $resourceURi = "$server/rest/api/latest/issue/{0}?deleteSubtasks={1}" + + if ($Force) { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] -Force was passed. Backing up current ConfirmPreference [$ConfirmPreference] and setting to None" + $oldConfirmPreference = $ConfirmPreference + $ConfirmPreference = 'None' + } + } + + process { + + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + foreach ($_issue in $Issue) { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_issue [$_issue]" + + $issueObj = Get-JiraIssue -InputObject $_issue -Credential $Credential -ErrorAction Stop + + $parameter = @{ + URI = $resourceURi -f $issueObj.Key,$IncludeSubTasks + Method = "DELETE" + Credential = $Credential + } + + $TargetText = "[$($issueObj.Key)] $($issueObj.Summary)" + If ($IncludeSubTasks) { + $ActionText = "Remove issue and sub-tasks" + } Else { + $ActionText = "Remove issue" + } + + if ($PSCmdlet.ShouldProcess($TargetText, $ActionText)) { + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter + } + } + + } + + end { + if ($Force) { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Restoring ConfirmPreference to [$oldConfirmPreference]" + $ConfirmPreference = $oldConfirmPreference + } + + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" + } +} diff --git a/docs/en-US/commands/Remove-JiraIssue.md b/docs/en-US/commands/Remove-JiraIssue.md new file mode 100644 index 00000000..55202893 --- /dev/null +++ b/docs/en-US/commands/Remove-JiraIssue.md @@ -0,0 +1,181 @@ +--- +external help file: JiraPS-help.xml +Module Name: JiraPS +online version: +schema: 2.0.0 +--- + +# Remove-JiraIssue + +## SYNOPSIS + +Removes an existing issue from JIRA. + +## SYNTAX + +```powershell +Remove-JiraIssue [-Issue] [-IncludeSubTasks] [[-Credential] ] [-Force] [-WhatIf] + [-Confirm] [] +``` + +## DESCRIPTION + +This function will remove an issue from Jira. +Deleting an issue removes it permanently from JIRA, including all of its comments and attachments. + +If you have completed an issue, it should usually be resolved or closed - not deleted. + +If an issue includes sub-tasks, these are deleted as well. + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +Remove-JiraUser -Issue ABC-123 +``` + +Removes issue \[ABC-123\] from JIRA. + +### EXAMPLE 2 + +```powershell +Remove-JiraUser -Issue ABC-124 -IncludeSubTasks +``` + +Removes issue \[ABC-124\] from JIRA, including any subtasks therein. + +### EXAMPLE 3 + +```powershell +Get-JiraIssue -Query "Project = ABC AND label = NeedsDeletion" | Remove-JiraUser -IncludeSubTasks +``` + +Removes all issues from project ABC (including their subtasks) that have the label "NeedsDeletion". + +## PARAMETERS + +### -Issue + +One or more issues to delete. These can be specified as: + +* Issue key(s) (e.g. `[ABC-123]`) +* Numerical ID(s) +* Object(s) to delete (such as ones returned from `Get-JiraIssue`) + +```yaml +Type: Object[] +Parameter Sets: (All) +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -IncludeSubTasks + +Removes any subtasks associated with the issue(s) to be deleted. + +If the issue has no subtasks, this parameter is ignored. If the issue has subtasks and this parameter is missing, then the issue will not be deleted and an error will be returned. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Credential + +Credentials to use to connect to JIRA. + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Force + +Suppress user confirmation. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +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] + +## OUTPUTS + +### Output (if any) + +## NOTES + +If the issue has subtasks you must include the parameter IncludeSubTasks to delete the issue. You cannot delete an issue without its subtasks also being deleted. + +This function requires either the \`-Credential\` parameter to be passed or a persistent JIRA session. +See \`New-JiraSession\` for more details. + +## RELATED LINKS From 750cd9f8fb94326af38457b71ea6c5556f598901 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Fri, 25 May 2018 17:24:16 -0700 Subject: [PATCH 18/83] Make Remove-JiraIssue "Object" param positional; Only call Get-JiraIssue when needed --- JiraPS/Public/Remove-JiraIssue.ps1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index 35fdfaa6..560b6791 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -4,7 +4,11 @@ function Remove-JiraIssue { SupportsShouldProcess )] param ( - [Parameter( Mandatory, ValueFromPipeline )] + [Parameter( + Mandatory, + ValueFromPipeline, + Position = 0 + )] [ValidateNotNullOrEmpty()] [ValidateScript( { @@ -63,7 +67,11 @@ function Remove-JiraIssue { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_issue [$_issue]" - $issueObj = Get-JiraIssue -InputObject $_issue -Credential $Credential -ErrorAction Stop + if (("JiraPS.Issue" -notin $_issue.PSObject.TypeNames)) { + $issueObj = Get-JiraIssue -Key $_issue -Credential $Credential -ErrorAction Stop + } Else { + $issueObj = $_ + } $parameter = @{ URI = $resourceURi -f $issueObj.Key,$IncludeSubTasks From 2116117ab8efc1d34037d76daa8f39a78a559237 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Tue, 29 May 2018 12:11:52 -0700 Subject: [PATCH 19/83] Use $issueObj (with implied .ToString()) in $PSCmdlet.ShouldProcess() --- JiraPS/Public/Remove-JiraIssue.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index 560b6791..e3b1e9db 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -79,14 +79,14 @@ function Remove-JiraIssue { Credential = $Credential } - $TargetText = "[$($issueObj.Key)] $($issueObj.Summary)" + If ($IncludeSubTasks) { $ActionText = "Remove issue and sub-tasks" } Else { $ActionText = "Remove issue" } - if ($PSCmdlet.ShouldProcess($TargetText, $ActionText)) { + if ($PSCmdlet.ShouldProcess($issueoBj, $ActionText)) { Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" Invoke-JiraMethod @parameter From 4e71efa5cba7ef0dc95a6098f4197f6a79d9452c Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Tue, 29 May 2018 12:17:18 -0700 Subject: [PATCH 20/83] Add additional information to Remove-JiraIssue doc frontmatter --- docs/en-US/commands/Remove-JiraIssue.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en-US/commands/Remove-JiraIssue.md b/docs/en-US/commands/Remove-JiraIssue.md index 55202893..48ebaf23 100644 --- a/docs/en-US/commands/Remove-JiraIssue.md +++ b/docs/en-US/commands/Remove-JiraIssue.md @@ -1,8 +1,11 @@ --- external help file: JiraPS-help.xml Module Name: JiraPS -online version: +online version: https://atlassianps.org/docs/JiraPS/commands/Remove-JiraIssue/ +locale: en-US schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Remove-JiraIssue/ --- # Remove-JiraIssue From 2b5215ac6babbe6b13ae6e36b232d5b956a3112b Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Tue, 29 May 2018 12:27:55 -0700 Subject: [PATCH 21/83] Add alias on -IncludeSubTasks to match Jira API terminology --- JiraPS/Public/Remove-JiraIssue.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index e3b1e9db..d84dbd76 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -35,6 +35,7 @@ function Remove-JiraIssue { $Issue, [Switch] + [Alias("deleteSubtasks")] $IncludeSubTasks, [PSCredential] From d687cffe45f11c81f5195f49dfd52b551f1738ce Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Tue, 29 May 2018 15:11:00 -0700 Subject: [PATCH 22/83] Forced explicit .ToString on $PSCmdlet.ShouldProcess() --- JiraPS/Public/Remove-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index d84dbd76..b062eac6 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -87,7 +87,7 @@ function Remove-JiraIssue { $ActionText = "Remove issue" } - if ($PSCmdlet.ShouldProcess($issueoBj, $ActionText)) { + if ($PSCmdlet.ShouldProcess($issueObj.ToString(), $ActionText)) { Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" Invoke-JiraMethod @parameter From cea2e6ddc50a18a8d9f6f845f5af7958efcc5836 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Tue, 29 May 2018 15:32:47 -0700 Subject: [PATCH 23/83] Updated -Credential parameter declaration on Remove-JiraIssue --- JiraPS/Public/Remove-JiraIssue.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index b062eac6..27680a98 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -38,7 +38,8 @@ function Remove-JiraIssue { [Alias("deleteSubtasks")] $IncludeSubTasks, - [PSCredential] + [System.Management.Automation.CredentialAttribute()] + [System.Management.Automation.PSCredential] $Credential, [Switch] From cb4c8080500cd5c4d9de11bf3fe42644c4ead621 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 30 May 2018 09:03:22 +0200 Subject: [PATCH 24/83] Fixed exporting of function alias in dev environment --- JiraPS/JiraPS.psm1 | 2 +- Tests/Get-JiraServerInformation.Tests.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/JiraPS/JiraPS.psm1 b/JiraPS/JiraPS.psm1 index c4cac996..0a4d6fa4 100644 --- a/JiraPS/JiraPS.psm1 +++ b/JiraPS/JiraPS.psm1 @@ -34,5 +34,5 @@ foreach ($file in @($PublicFunctions + $PrivateFunctions)) { throw $_ } } -Export-ModuleMember -Function $PublicFunctions.BaseName +Export-ModuleMember -Function $PublicFunctions.BaseName -Alias * #endregion LoadFunctions diff --git a/Tests/Get-JiraServerInformation.Tests.ps1 b/Tests/Get-JiraServerInformation.Tests.ps1 index cddd5c1d..55bdfe0c 100644 --- a/Tests/Get-JiraServerInformation.Tests.ps1 +++ b/Tests/Get-JiraServerInformation.Tests.ps1 @@ -49,7 +49,7 @@ Describe "Get-JiraServerInformation" { It "Answers to the alias 'Get-JiraServerInfo'" { $thisAlias = (Get-Alias -Name "Get-JiraServerInfo") $thisAlias.ResolvedCommandName | Should Be "Get-JiraServerInformation" - $thisAlias.Source | Should Be "JiraPS" + $thisAlias.ModuleName | Should Be "JiraPS" } } } From b19123c337dd7ebe4d0f3534a35cdfe6054f1628 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 30 May 2018 10:55:57 +0200 Subject: [PATCH 25/83] Skip PSSciptAnalyzer, as it is not working in PSv3 --- Tests/JiraPS.Tests.ps1 | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Tests/JiraPS.Tests.ps1 b/Tests/JiraPS.Tests.ps1 index 4a8ed5bd..635e734e 100644 --- a/Tests/JiraPS.Tests.ps1 +++ b/Tests/JiraPS.Tests.ps1 @@ -183,16 +183,18 @@ Describe "JiraPS" { } Context 'PSScriptAnalyzer Rules' { - Import-Module $manifestFile -Force -ErrorAction Stop + if ($PSVersionTable.PSVersion.Major -gt 3) { + Import-Module $manifestFile -Force -ErrorAction Stop - $analysis = Invoke-ScriptAnalyzer -Path "$moduleRoot" -Recurse -Settings "$projectRoot/PSScriptAnalyzerSettings.psd1" - $scriptAnalyzerRules = Get-ScriptAnalyzerRule + $analysis = Invoke-ScriptAnalyzer -Path "$moduleRoot" -Recurse -Settings "$projectRoot/PSScriptAnalyzerSettings.psd1" + $scriptAnalyzerRules = Get-ScriptAnalyzerRule - forEach ($rule in $scriptAnalyzerRules) { - It "Should pass $rule" { - if (($analysis) -and ($analysis.RuleName -contains $rule)) { - $analysis | Where-Object RuleName -eq $rule -OutVariable failures | Out-Default - $failures.Count | Should Be 0 + forEach ($rule in $scriptAnalyzerRules) { + It "Should pass $rule" { + if (($analysis) -and ($analysis.RuleName -contains $rule)) { + $analysis | Where-Object RuleName -eq $rule -OutVariable failures | Out-Default + $failures.Count | Should Be 0 + } } } } From 5677a3b584a100062cf8267c7b02520f82344585 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 30 May 2018 12:45:10 +0200 Subject: [PATCH 26/83] Removed debugging code --- JiraPS/JiraPS.psm1 | 3 +-- JiraPS/Public/Invoke-JiraMethod.ps1 | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/JiraPS/JiraPS.psm1 b/JiraPS/JiraPS.psm1 index 0a4d6fa4..c251e311 100644 --- a/JiraPS/JiraPS.psm1 +++ b/JiraPS/JiraPS.psm1 @@ -30,8 +30,7 @@ foreach ($file in @($PublicFunctions + $PrivateFunctions)) { $errorTarget = $file $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget $errorItem.ErrorDetails = "Failed to import function $($file.BaseName)" - # throw $errorItem - throw $_ + throw $errorItem } } Export-ModuleMember -Function $PublicFunctions.BaseName -Alias * diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 4312fa0f..2cecd952 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -48,7 +48,7 @@ function Invoke-JiraMethod { "Accept-Charset" = "utf-8" } # Bug in PSv3's .Net API - if ($PSVersionTable.PSVersion.Major -eq 3) { + if ($PSVersionTable.PSVersion.Major -gt 3) { $_headers["Accept"] = "application/json" } foreach ($item in $Headers.Key) { $_headers[$item] = $Headers[$item] } From a8d216598abc4555664fbfdb81dedb95e0a5a32f Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Wed, 30 May 2018 14:43:47 -0700 Subject: [PATCH 27/83] Fix incorrect variable usage in Remove-JiraIssue foreach loop --- JiraPS/Public/Remove-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index 27680a98..8695bbc2 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -72,7 +72,7 @@ function Remove-JiraIssue { if (("JiraPS.Issue" -notin $_issue.PSObject.TypeNames)) { $issueObj = Get-JiraIssue -Key $_issue -Credential $Credential -ErrorAction Stop } Else { - $issueObj = $_ + $issueObj = $_issue } $parameter = @{ From 8f1f41e1df0c7a15c455e93e9c610eb036a70f33 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Wed, 30 May 2018 14:44:06 -0700 Subject: [PATCH 28/83] =?UTF-8?q?Add=20Pester=20tests=20for=20Remove-JiraI?= =?UTF-8?q?ssue=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tests/Remove-JiraIssue.Tests.ps1 | 272 +++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 Tests/Remove-JiraIssue.Tests.ps1 diff --git a/Tests/Remove-JiraIssue.Tests.ps1 b/Tests/Remove-JiraIssue.Tests.ps1 new file mode 100644 index 00000000..88bbedbf --- /dev/null +++ b/Tests/Remove-JiraIssue.Tests.ps1 @@ -0,0 +1,272 @@ +Describe "Remove-JiraIssue" { + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + $script:ShowMockData = $true + + $jiraServer = 'http://jiraserver.example.com' + + $TestIssueJSONs = @{ + + # basic issue + 'TEST-1' = @' + { + "expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations", + "id": "58159", + "self": "https://jiraserver.example.com/rest/api/2/issue/58159", + "key": "TEST-1", + "fields": { + "subtasks": [], + "project": { + "self": "https://jiraserver.example.com/rest/api/2/project/14801", + "id": "14801", + "key": "TEST", + "name": "TEST - Service Desk", + "avatarUrls": { + "48x48": "https://jiraserver.example.com/secure/projectavatar?avatarId=12003", + "24x24": "https://jiraserver.example.com/secure/projectavatar?size=small&avatarId=12003", + "16x16": "https://jiraserver.example.com/secure/projectavatar?size=xsmall&avatarId=12003", + "32x32": "https://jiraserver.example.com/secure/projectavatar?size=medium&avatarId=12003" + } + }, + "aggregatetimespent": null, + "resolutiondate": null, + "workratio": -1, + "description": "Test issue.", + "summary": "Test Issue", + "comment": { + "comments": [], + "maxResults": 0, + "total": 0, + "startAt": 0 + } + } + } +'@ + # issue w/ subtasks + 'TEST-2' = @' + { + "expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations", + "id": "58160", + "self": "https://jiraserver.example.com/rest/api/2/issue/58160", + "key": "TEST-2", + "fields": { + "subtasks": [ + { + "id": "58161", + "key": "TEST-3", + "self": "https://jiraserver.example.com/rest/api/2/issue/58161", + "fields": { + "summary": "Test Sub-Task", + "status": { + "self": "https://jiraserver.example.com/rest/api/2/status/11202", + "description": "This was auto-generated by JIRA Service Desk during workflow import", + "iconUrl": "https://jiraserver.example.com/images/icons/status_generic.gif", + "name": "Open", + "id": "11202", + "statusCategory": { + "self": "https://jiraserver.example.com/rest/api/2/statuscategory/2", + "id": 2, + "key": "new", + "colorName": "blue-gray", + "name": "To Do" + } + }, + "priority": { + "self": "https://jiraserver.example.com/rest/api/2/priority/4", + "iconUrl": "https://jiraserver.example.com/images/icons/priorities/minor.svg", + "name": "Medium", + "id": "4" + }, + "issuetype": { + "self": "https://jiraserver.example.com/rest/api/2/issuetype/5", + "id": "5", + "description": "The sub-task of the issue", + "iconUrl": "https://jiraserver.example.com/secure/viewavatar?size=xsmall&avatarId=11016&avatarType=issuetype", + "name": "Sub-task", + "subtask": true, + "avatarId": 11016 + } + } + } + ], + "project": { + "self": "https://jiraserver.example.com/rest/api/2/project/14801", + "id": "14801", + "key": "TEST", + "name": "TEST - Service Desk", + "avatarUrls": { + "48x48": "https://jiraserver.example.com/secure/projectavatar?avatarId=12003", + "24x24": "https://jiraserver.example.com/secure/projectavatar?size=small&avatarId=12003", + "16x16": "https://jiraserver.example.com/secure/projectavatar?size=xsmall&avatarId=12003", + "32x32": "https://jiraserver.example.com/secure/projectavatar?size=medium&avatarId=12003" + } + }, + "description": "Test issue with a sub-task attached.", + "summary": "Test Parent-Task Issue", + "comment": { + "comments": [], + "maxResults": 0, + "total": 0, + "startAt": 0 + } + } + } +'@ + # the sub-task itself + 'TEST-3' = @' + { + "expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations", + "id": "58161", + "self": "https://jiraserver.example.com/rest/api/2/issue/58161", + "key": "TEST-3", + "fields": { + "parent": { + "id": "58160", + "key": "TEST-2", + "self": "https://jiraserver.example.com/rest/api/2/issue/58160", + "fields": { + "summary": "Test Parent-Task Issue", + "status": { + "self": "https://jiraserver.example.com/rest/api/2/status/1", + "description": "The issue is new and has not been looked at yet.", + "iconUrl": "https://jiraserver.example.com/images/icons/statuses/open.png", + "name": "OPENED", + "id": "1", + "statusCategory": { + "self": "https://jiraserver.example.com/rest/api/2/statuscategory/2", + "id": 2, + "key": "new", + "colorName": "blue-gray", + "name": "To Do" + } + }, + "priority": { + "self": "https://jiraserver.example.com/rest/api/2/priority/4", + "iconUrl": "https://jiraserver.example.com/images/icons/priorities/minor.svg", + "name": "Medium", + "id": "4" + }, + "issuetype": { + "self": "https://jiraserver.example.com/rest/api/2/issuetype/3", + "id": "3", + "description": "A task that needs to be done.", + "iconUrl": "https://jiraserver.example.com/secure/viewavatar?size=xsmall&avatarId=11018&avatarType=issuetype", + "name": "Task", + "subtask": false, + "avatarId": 11018 + } + } + }, + "subtasks": [], + "project": { + "self": "https://jiraserver.example.com/rest/api/2/project/14801", + "id": "14801", + "key": "TEST", + "name": "TEST - Service Desk", + "avatarUrls": { + "48x48": "https://jiraserver.example.com/secure/projectavatar?avatarId=12003", + "24x24": "https://jiraserver.example.com/secure/projectavatar?size=small&avatarId=12003", + "16x16": "https://jiraserver.example.com/secure/projectavatar?size=xsmall&avatarId=12003", + "32x32": "https://jiraserver.example.com/secure/projectavatar?size=medium&avatarId=12003" + } + }, + "description": "Test sub-task.", + "summary": "Test Sub-Task", + "comment": { + "comments": [], + "maxResults": 0, + "total": 0, + "startAt": 0 + } + } + } +'@ + + } + + Mock Get-JiraConfigServer -ModuleName JiraPS { + Write-Output $jiraServer + } + + Mock Get-JiraIssue { + $obj = $TestIssueJSONs[$Key] | ConvertFrom-Json + + $obj.PSObject.TypeNames.Insert(0, 'JiraPS.Issue') + + $obj | Add-Member -MemberType ScriptMethod -Name ToString -Value {return ""} -Force + return $obj + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$URI -like "$jiraServer/rest/api/*/issue/TEST-1?*" -and $Method -eq "Delete"} { + return $null + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$URI -like "$jiraServer/rest/api/*/issue/TEST-2?deleteSubTasks=False" -and $Method -eq "Delete"} { + $MockedResponse = @" + { + "errorMessages": [ + "The issue 'TEST-2' has subtasks. You must specify the 'deleteSubtasks' parameter to delete this issue and all its subtasks." + ], + "errors": {} + } +"@ | ConvertFrom-Json + Resolve-JiraError $MockedResponse -WriteError + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$URI -like "$jiraServer/rest/api/*/issue/TEST-2?deleteSubTasks=True" -and $Method -eq "Delete"} { + return $null + } + + # 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 + ############# + + Context "Sanity checking" { + $command = Get-Command -Name Remove-JiraIssue + + defParam $command 'Issue' + defParam $command 'IncludeSubTasks' + defParam $command 'Credential' + } + + Context "Functionality" { + + It "Accepts generic object with the correct properties" { + { + $issue = Get-JiraIssue -Key TEST-1 + Remove-JiraIssue -Issue $issue -Force + } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Accepts a JiraPS.Issue object over the pipeline" { + { Get-JiraIssue -Key TEST-1 | Remove-JiraIssue -Force} | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Throws on issues with subtasks" { + { Get-JiraIssue -Key TEST-2 | Remove-JiraIssue -Force -ErrorAction Stop} | Should Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Passes on issues with subtasks and -DeleteSubTasks" { + { Get-JiraIssue -Key TEST-2 | Remove-JiraIssue -IncludeSubTasks -Force} | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + + It "Validates pipeline input" { + { @{id = 1} | Remove-JiraIssue -ErrorAction SilentlyContinue } | Should Throw + } + } + } +} From 639c6081df25c01715bc882440bf5d1b7ec453f8 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 10:39:53 -0700 Subject: [PATCH 29/83] Add default value for -Credential --- JiraPS/Public/Remove-JiraIssue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index 8695bbc2..801d3c33 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -40,7 +40,7 @@ function Remove-JiraIssue { [System.Management.Automation.CredentialAttribute()] [System.Management.Automation.PSCredential] - $Credential, + $Credential = [System.Management.Automation.PSCredential]::Empty, [Switch] $Force From 157dcd4b09b449b79639e6c1a0b3738a4995cbf9 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 10:40:39 -0700 Subject: [PATCH 30/83] Remove debugging lines from Remove-JiraIssue tests --- Tests/Remove-JiraIssue.Tests.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/Remove-JiraIssue.Tests.ps1 b/Tests/Remove-JiraIssue.Tests.ps1 index 88bbedbf..cf7db7fe 100644 --- a/Tests/Remove-JiraIssue.Tests.ps1 +++ b/Tests/Remove-JiraIssue.Tests.ps1 @@ -5,8 +5,6 @@ Describe "Remove-JiraIssue" { . "$PSScriptRoot/Shared.ps1" - $script:ShowMockData = $true - $jiraServer = 'http://jiraserver.example.com' $TestIssueJSONs = @{ From 1627090ffb72762e4cc905d6b8df7bac8a60ad9c Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 11:06:08 -0700 Subject: [PATCH 31/83] Change parameter validation to accommodate PSv3 --- JiraPS/Public/Remove-JiraIssue.ps1 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index 801d3c33..e4a86912 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -13,12 +13,11 @@ function Remove-JiraIssue { [ValidateScript( { if (("JiraPS.Issue" -notin $_.PSObject.TypeNames) -and (($_ -isnot [String]))) { - $errorItem = [System.Management.Automation.ErrorRecord]::new( - ([System.ArgumentException]"Invalid Type for Parameter"), - 'ParameterType.NotJiraIssue', - [System.Management.Automation.ErrorCategory]::InvalidArgument, - $_ - ) + $exception = ([System.ArgumentException]"Invalid Type for Parameter") #fix code highlighting] + $errorId = 'ParameterType.NotJiraIssue' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName "System.Management.Automation.ErrorRecord" -ArgumentList $exception,$errorId,$errorCategory,$errorTarget $errorItem.ErrorDetails = "Wrong object type provided for Issue. Expected [JiraPS.Issue] or [String], but was $($_.GetType().Name)" $PSCmdlet.ThrowTerminatingError($errorItem) <# From a2d1a7bcec9267d6fdbea2f8f9c9d3e36675a1e2 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 14:00:08 -0700 Subject: [PATCH 32/83] Fix misleading comment --- JiraPS/Public/Invoke-JiraMethod.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 2cecd952..5308e9c1 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -120,8 +120,10 @@ function Invoke-JiraMethod { # Invoke-WebRequest is hard-coded to throw an exception if the Web request returns a 4xx or 5xx error. # This is the best workaround I can find to retrieve the actual results of the request. $webResponse = $_ + # ErrorDetails behavior is erratic and may not always be available + # See https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/17142518--errordetails-is-null-when-invoke-webrequest-or + # PSv6+ appears to be unaffected if ($webResponse.ErrorDetails) { - # In PowerShellCore (v6+), the response body is available as string $responseBody = $webResponse.ErrorDetails.Message } else { From 248a372fa74e5ad9426c95fc0ad7563455bbe88d Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 14:01:18 -0700 Subject: [PATCH 33/83] Split error handler if-block to account for $responseBody being pre-set --- JiraPS/Public/Invoke-JiraMethod.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 5308e9c1..f0e33c4e 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -150,7 +150,9 @@ function Invoke-JiraMethod { $readStream = New-Object -TypeName System.IO.StreamReader -ArgumentList ($webResponse.GetResponseStream()) $responseBody = $readStream.ReadToEnd() $readStream.Close() + } + If ($responseBody) { # Clear the body in case it is not a JSON (but rather html) if ($responseBody -match "^[\s\t]*\") { $responseBody = '{"errorMessages": "Invalid server response. HTML returned."}' } From 9cc4ca7b346bbb63c82ed92ea39df473f32431b8 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 14:05:09 -0700 Subject: [PATCH 34/83] Added handler for API responses that are neither JSON or HTML --- JiraPS/Public/Invoke-JiraMethod.ps1 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index f0e33c4e..c7dc9048 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -158,7 +158,18 @@ function Invoke-JiraMethod { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Retrieved body of HTTP response for more information about the error (`$responseBody)" Write-Debug "[$($MyInvocation.MyCommand.Name)] Got the following error as `$responseBody" - $result = ConvertFrom-Json -InputObject $responseBody + try { + $result = ConvertFrom-Json -InputObject $responseBody + + } catch [ArgumentException] { # handle $responseBody being neither JSON nor HTML + $result = @{ + errorMessages = @( + "Non-JSON/HTML response returned from JIRA API" + $responseBody + ) + } + } + } } From 04bc6207a76bdae919068498d1f8153e6ea742f5 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 14:09:15 -0700 Subject: [PATCH 35/83] Mark errorMessages as error-state members in result interpreter --- JiraPS/Public/Invoke-JiraMethod.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index c7dc9048..76774da1 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -193,7 +193,7 @@ function Invoke-JiraMethod { } if ($result) { - if (Get-Member -Name "Errors" -InputObject $result -ErrorAction SilentlyContinue) { + if (Get-Member -Name "Errors","errorMessages" -InputObject $result -ErrorAction SilentlyContinue) { Resolve-JiraError $result -WriteError -Cmdlet $Cmdlet } else { From 833c277c93cfdb60a09c3a8e9e4264efc52f77b7 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 14:14:06 -0700 Subject: [PATCH 36/83] Remove unnecessary line from error-handler --- JiraPS/Public/Invoke-JiraMethod.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 76774da1..e4535752 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -162,9 +162,8 @@ function Invoke-JiraMethod { $result = ConvertFrom-Json -InputObject $responseBody } catch [ArgumentException] { # handle $responseBody being neither JSON nor HTML - $result = @{ + $result = [PSCustomObject]@{ errorMessages = @( - "Non-JSON/HTML response returned from JIRA API" $responseBody ) } From 5068109a8f521aa219aa8339668526109adb51c3 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 15:05:36 -0700 Subject: [PATCH 37/83] Fix Test-ServerResponse call to handle exceptions with ErrorDetails --- JiraPS/Public/Invoke-JiraMethod.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index e4535752..59deba97 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -131,7 +131,13 @@ function Invoke-JiraMethod { } } - Test-ServerResponse -InputObject $webResponse -Cmdlet $Cmdlet + if ($WebResponse.ErrorDetails) { + Test-ServerResponse -InputObject $webResponse.Exception.Response -Cmdlet $Cmdlet + } Else { + Test-ServerResponse -InputObject $webResponse -Cmdlet $Cmdlet + } + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Executed WebRequest. Access `$webResponse to see details" From dfbe1317bcab44c29fd1e42f4b213963b372ca51 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 15:09:19 -0700 Subject: [PATCH 38/83] Ensure System.Net.Http assembly is loaded when importing (as Test-ServerResponse requires it) --- JiraPS/JiraPS.psm1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/JiraPS/JiraPS.psm1 b/JiraPS/JiraPS.psm1 index c251e311..0b11a9ac 100644 --- a/JiraPS/JiraPS.psm1 +++ b/JiraPS/JiraPS.psm1 @@ -10,7 +10,12 @@ # Load Web assembly when needed # PowerShell Core has the assembly preloaded if (!("System.Web.HttpUtility" -as [Type])) { - Add-Type -Assembly System.Web + Add-Type -AssemblyName "System.Web" +} +# Load System.Net.Http when needed +# PowerShell Core has the assembly preloaded +if (!("System.Net.Http.HttpRequestException" -as [Type])) { + Add-Type -AssemblyName "System.Net.Http" } #endregion Dependencies From 575b88837704cd78a78e53ade5c264639a0af5de Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Thu, 31 May 2018 16:52:49 -0700 Subject: [PATCH 39/83] Remove unit test dependency on Resolve-JiraError --- Tests/Remove-JiraIssue.Tests.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Tests/Remove-JiraIssue.Tests.ps1 b/Tests/Remove-JiraIssue.Tests.ps1 index cf7db7fe..7d30fb13 100644 --- a/Tests/Remove-JiraIssue.Tests.ps1 +++ b/Tests/Remove-JiraIssue.Tests.ps1 @@ -204,6 +204,8 @@ Describe "Remove-JiraIssue" { } Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$URI -like "$jiraServer/rest/api/*/issue/TEST-2?deleteSubTasks=False" -and $Method -eq "Delete"} { + + Write-Error -Exception -ErrorId $MockedResponse = @" { "errorMessages": [ @@ -212,7 +214,17 @@ Describe "Remove-JiraIssue" { "errors": {} } "@ | ConvertFrom-Json - Resolve-JiraError $MockedResponse -WriteError + + + $Exception = ([System.ArgumentException]"Server responded with Error") + $errorId = "ServerResponse" + $errorCategory = 'NotSpecified' + $errorTarget = $MockedResponse + + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $Exception,$errorId,$errorCategory,$errorTarget + $errorItem.ErrorDetails = "Jira encountered an error: [The issue 'TEST-2' has subtasks. You must specify the 'deleteSubtasks' parameter to delete this issue and all its subtasks.]" + + $PSCmdlet.WriteError($errorItem) } Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$URI -like "$jiraServer/rest/api/*/issue/TEST-2?deleteSubTasks=True" -and $Method -eq "Delete"} { From c78fb8123ae25a51a211a77406424216e700bae5 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Fri, 1 Jun 2018 23:28:50 +0200 Subject: [PATCH 40/83] Fixed installation of PSScriptAnalyzer --- Tools/build.requirements.psd1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Tools/build.requirements.psd1 b/Tools/build.requirements.psd1 index 2c0e1b26..7c0668f0 100644 --- a/Tools/build.requirements.psd1 +++ b/Tools/build.requirements.psd1 @@ -17,5 +17,10 @@ Version = "4.1.1" } platyPS = "latest" - PSScriptAnalyzer = "latest" + PSScriptAnalyzer = @{ + Parameters = @{ + SkipPublisherCheck = $true + } + Version = "latest" + } } From 23ab6c65a65e550ad376c952b35f58fe7e81c954 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sat, 2 Jun 2018 09:14:14 +0200 Subject: [PATCH 41/83] IMplemented workaround to PSScriptAnalyzer error message --- Tests/JiraPS.Tests.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tests/JiraPS.Tests.ps1 b/Tests/JiraPS.Tests.ps1 index 635e734e..3512d171 100644 --- a/Tests/JiraPS.Tests.ps1 +++ b/Tests/JiraPS.Tests.ps1 @@ -186,7 +186,13 @@ Describe "JiraPS" { if ($PSVersionTable.PSVersion.Major -gt 3) { Import-Module $manifestFile -Force -ErrorAction Stop - $analysis = Invoke-ScriptAnalyzer -Path "$moduleRoot" -Recurse -Settings "$projectRoot/PSScriptAnalyzerSettings.psd1" + $invokeScriptAnalyzerSplat = @{ + Path = "$moduleRoot" + Settings = "$projectRoot/PSScriptAnalyzerSettings.psd1" + Recurse = $true + ErrorAction = 'SilentlyContinue' + } + $analysis = Invoke-ScriptAnalyzer @invokeScriptAnalyzerSplat $scriptAnalyzerRules = Get-ScriptAnalyzerRule forEach ($rule in $scriptAnalyzerRules) { From 27d770130255fa88bf2ccb00bf94d7ba1c8e6e1d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 4 Jun 2018 14:34:18 +0200 Subject: [PATCH 42/83] reduced complexity of Invoke-JiraMethod extracted several blocks into private function to make the code more readable --- JiraPS/Private/Join-Hashtable.ps1 | 38 ++++++ .../Private/Resolve-DefaultParameterValue.ps1 | 76 ++++++++++++ JiraPS/Private/Resolve-ErrorWebResponse.ps1 | 83 +++++++++++++ JiraPS/Public/Invoke-JiraMethod.ps1 | 115 ++++++------------ 4 files changed, 235 insertions(+), 77 deletions(-) create mode 100644 JiraPS/Private/Join-Hashtable.ps1 create mode 100644 JiraPS/Private/Resolve-DefaultParameterValue.ps1 create mode 100644 JiraPS/Private/Resolve-ErrorWebResponse.ps1 diff --git a/JiraPS/Private/Join-Hashtable.ps1 b/JiraPS/Private/Join-Hashtable.ps1 new file mode 100644 index 00000000..5371b451 --- /dev/null +++ b/JiraPS/Private/Join-Hashtable.ps1 @@ -0,0 +1,38 @@ +function Join-Hashtable { + <# + .SYNOPSIS + Combines multiple hashtables into a single table. + + .DESCRIPTION + Combines multiple hashtables into a single table. + On multiple identic keys, the last wins. + + .PARAMETER Hashtable + The tables to merge. + + .EXAMPLE + PS C:\> Join-Hashtable -Hashtable $Hash1, $Hash2 + + Merges the hashtables contained in $Hash1 and $Hash2 into a single hashtable. +#> + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [AllowNull()] + [System.Collections.IDictionary[]] + $Hashtable + ) + begin { + $table = @{ } + } + process { + foreach ($item in $Hashtable) { + foreach ($key in $item.Keys) { + $table[$key] = $item[$key] + } + } + } + end { + $table + } +} diff --git a/JiraPS/Private/Resolve-DefaultParameterValue.ps1 b/JiraPS/Private/Resolve-DefaultParameterValue.ps1 new file mode 100644 index 00000000..781ccc94 --- /dev/null +++ b/JiraPS/Private/Resolve-DefaultParameterValue.ps1 @@ -0,0 +1,76 @@ +function Resolve-DefaultParameterValue { + <# + .SYNOPSIS + Used to filter and process default parameter values. + + .DESCRIPTION + This command picks all the default parameter values from a reference hashtable. + It then filters all that match a specified command and binds them to that specific command, narrowing its focus. + These get merged into either a new or a specified hashtable and returned. + + .PARAMETER Reference + The hashtable to pick default parameter valeus from. + + .PARAMETER CommandName + The commands to pick default parameter values for. + + .PARAMETER Target + The target hashtable to merge results into. + By default an empty hashtable is used. + + .PARAMETER ParameterName + Only resolve for specific parameter names. + + .EXAMPLE + PS C:\> Resolve-DefaultParameterValue -Reference $global:PSDefaultParameterValues -CommandName 'Invoke-WebRequest' + + Returns a hashtable containing all default parameter values in the global scope affecting the command 'Invoke-WebRequest'. +#> + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [System.Collections.Hashtable] + $Reference, + + [Parameter(Mandatory = $true)] + [String[]] + $CommandName, + + [System.Collections.Hashtable] + $Target = @{ }, + + [String[]] + $ParameterName = "*" + ) + + begin { + $defaultItems = New-Object -TypeName System.Collections.ArrayList + foreach ($key in $Reference.Keys) { + $null = $defaultItems.Add( + [PSCustomObject]@{ + Key = $key + Value = $Reference[$key] + Command = $key.Split(":")[0] + Parameter = $key.Split(":")[1] + } + ) + } + } + process { + foreach ($command in $CommandName) { + foreach ($item in $defaultItems) { + if ($command -notlike $item.Command) { continue } + + foreach ($parameter in $ParameterName) { + if ($item.Parameter -like $parameter) { + if ($parameter -ne "*") { $Target["$($command):$($parameter)"] = $item.Value } + else { $Target["$($command):$($item.Parameter)"] = $item.Value } + } + } + } + } + } + end { + $Target + } +} diff --git a/JiraPS/Private/Resolve-ErrorWebResponse.ps1 b/JiraPS/Private/Resolve-ErrorWebResponse.ps1 new file mode 100644 index 00000000..4528350c --- /dev/null +++ b/JiraPS/Private/Resolve-ErrorWebResponse.ps1 @@ -0,0 +1,83 @@ +function Resolve-ErrorWebResponse { + [CmdletBinding()] + param ( + $Exception, + + $StatusCode, + + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCmdlet] + $Cmdlet = $PSCmdlet + ) + + begin { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + + # Powershell v6+ populates the body of the response into the exception + if ($Exception.ErrorDetails) { + $responseBody = $Exception.ErrorDetails.Message + } + # Powershell v5.1- has the body of the response in a Stream in the Exception Response + else { + Write-Verbose 1 + $readStream = New-Object -TypeName System.IO.StreamReader -ArgumentList ($Exception.Exception.Response.GetResponseStream()) + $responseBody = $readStream.ReadToEnd() + $readStream.Close() + } + + if ($responseBody) { + # Clear the body in case it is not a JSON (but rather html) + if ($responseBody -match "^[\s\t]*\") { $responseBody = '{"errorMessages": "Invalid server response. HTML returned."}' } + + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Retrieved body of HTTP response for more information about the error (`$responseBody)" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Got the following error as `$responseBody" + + $exception = "Invalid Server Response" + $errorId = "InvalidResponse.Status$($StatusCode.value__)" + $errorCategory = "InvalidResult" + + try { + $responseObject = ConvertFrom-Json -InputObject $responseBody -ErrorAction Stop + Write-Debug "aaaa `$responseObject" + + foreach ($_error in ($responseObject.errorMessages + $responseObject.errors)) { + # $_error is a PSCustomObject - therefore can't be $false + if (-not $_error.ToString()) { break } + + $writeErrorSplat = @{ + Exception = $exception + ErrorId = $errorId + Category = $errorCategory + Message = $_error + TargetObject = $targetObject + Cmdlet = $Cmdlet + } + WriteError @writeErrorSplat + } + } + catch [ArgumentException] { + $writeErrorSplat = @{ + Exception = $exception + ErrorId = $errorId + Category = $errorCategory + Message = $responseBody + TargetObject = $targetObject + Cmdlet = $Cmdlet + } + WriteError @writeErrorSplat + } + catch { + $writeErrorSplat = @{ + Exception = $exception + ErrorId = $errorId + Category = $errorCategory + Message = "An unknown error ocurred." + TargetObject = $targetObject + Cmdlet = $Cmdlet + } + WriteError @writeErrorSplat + } + } + } +} diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index e8e82d5f..67695906 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -19,9 +19,11 @@ function Invoke-JiraMethod { [Hashtable] $Headers = @{}, - [Hashtable]$GetParameter = @{}, + [Hashtable] + $GetParameter = @{}, - [Switch]$Paging, + [Switch] + $Paging, [String] $InFile, @@ -54,43 +56,44 @@ function Invoke-JiraMethod { # load DefaultParameters for Invoke-WebRequest # as the global PSDefaultParameterValues is not used - $PSDefaultParameterValues = $global:PSDefaultParameterValues + $PSDefaultParameterValues = Resolve-DefaultParameterValue -Reference $global:PSDefaultParameterValues -CommandName 'Invoke-WebRequest' + #region Headers # Construct the Headers with the folling priority: # - Headers passes as parameters # - User's Headers in $PSDefaultParameterValues # - Module's default Headers - $_headers = $script:DefaultHeaders - if ($PSDefaultParameterValues.ContainsKey("Invoke-WebRequest:Headers")) { - $userSpecificHeaders = $PSDefaultParameterValues["Invoke-WebRequest:Headers"] - foreach ($item in $userSpecificHeaders.Key) { $_headers[$item] = $userSpecificHeaders[$item] } - } - foreach ($item in $Headers.Key) { $_headers[$item] = $Headers[$item] } + $_headers = Join-Hashtable -Hashtable $script:DefaultHeaders, $PSDefaultParameterValues["Invoke-WebRequest:Headers"], $Headers + #endregion Headers + #region Manage URI # Amend query from URI with GetParameter $uriQuery = ConvertTo-ParameterHash -Uri $Uri - foreach ($item in $uriQuery.Keys) { $GetParameter[$item] = $uriQuery[$item] } + $internalGetParameter = Join-Hashtable $GetParameter, $uriQuery + # And remove it from URI [Uri]$Uri = $Uri.GetLeftPart("Path") $PaginatedUri = $Uri # Use default PageSize - if (-not $GetParameter.ContainsKey("maxResults")) { - $GetParameter["maxResults"] = $script:DefaultPageSize + if (-not $internalGetParameter.ContainsKey("maxResults")) { + $internalGetParameter["maxResults"] = $script:DefaultPageSize } # Append GET parameters to URi if ($PSCmdlet.PagingParameters) { if ($PSCmdlet.PagingParameters.Skip) { - $GetParameter["startAt"] = $PSCmdlet.PagingParameters.Skip + $internalGetParameter["startAt"] = $PSCmdlet.PagingParameters.Skip } - if ($PSCmdlet.PagingParameters.First -lt $GetParameter["maxResults"]) { - $GetParameter["maxResults"] = $PSCmdlet.PagingParameters.First + if ($PSCmdlet.PagingParameters.First -lt $internalGetParameter["maxResults"]) { + $internalGetParameter["maxResults"] = $PSCmdlet.PagingParameters.First } } - [Uri]$PaginatedUri = "$PaginatedUri$(ConvertTo-GetParameter $GetParameter)" + [Uri]$PaginatedUri = "{0}{1}" -f $PaginatedUri, (ConvertTo-GetParameter $internalGetParameter) + #endregion Manage URI + #region Constructe IWR Parameter $splatParameters = @{ Uri = $PaginatedUri Method = $Method @@ -105,7 +108,6 @@ function Invoke-JiraMethod { if ($_headers.ContainsKey("Content-Type")) { $splatParameters["ContentType"] = $_headers["Content-Type"] $_headers.Remove("Content-Type") - $splatParameters["Headers"] = $_headers } if ($Body) { @@ -137,74 +139,42 @@ function Invoke-JiraMethod { if ($OutFile) { $splatParameters["OutFile"] = $OutFile } + #endregion Constructe IWR Parameter - # Invoke the API - Write-Verbose "[$($MyInvocation.MyCommand.Name)] $($splatParameters.Method) $($splatParameters.Uri)" - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoke-WebRequest with `$splatParameters: $($splatParameters | Out-String)" + #region Execute the actual query try { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] $($splatParameters.Method) $($splatParameters.Uri)" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoke-WebRequest with `$splatParameters: $($splatParameters | Out-String)" + # Invoke the API $webResponse = Invoke-WebRequest @splatParameters } catch { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed to get an answer from the server" - # Invoke-WebRequest is hard-coded to throw an exception if the Web request returns a 4xx or 5xx error. - # This is the best workaround I can find to retrieve the actual results of the request. - $webResponse = $_ - # ErrorDetails behavior is erratic and may not always be available - # See https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/17142518--errordetails-is-null-when-invoke-webrequest-or - # PSv6+ appears to be unaffected - if ($webResponse.ErrorDetails) { - $responseBody = $webResponse.ErrorDetails.Message - } - else { - $webResponse = $webResponse.Exception.Response - } - } - if ($WebResponse.ErrorDetails) { - Test-ServerResponse -InputObject $webResponse.Exception.Response -Cmdlet $Cmdlet - } Else { - Test-ServerResponse -InputObject $webResponse -Cmdlet $Cmdlet + $exception = $_ + $webResponse = $exception.Exception.Response } - - Write-Debug "[$($MyInvocation.MyCommand.Name)] Executed WebRequest. Access `$webResponse to see details" + Test-ServerResponse -InputObject $webResponse -Cmdlet $Cmdlet + #endregion Execute the actual query + } + process { if ($webResponse) { # In PowerShellCore (v6+) the StatusCode of an exception is somewhere else if (-not ($statusCode = $webResponse.StatusCode)) { - $statusCode = $webresponse.Exception.Response.StatusCode + $statusCode = $webResponse.Exception.Response.StatusCode } Write-Verbose "[$($MyInvocation.MyCommand.Name)] Status code: $($statusCode)" + #region Code 400+ if ($statusCode.value__ -ge 400) { - if ((!($responseBody)) -and ($webResponse | Get-Member -Name "GetResponseStream")) { - # Retrieve body of HTTP response - this contains more useful information about exactly why the error occurred - $readStream = New-Object -TypeName System.IO.StreamReader -ArgumentList ($webResponse.GetResponseStream()) - $responseBody = $readStream.ReadToEnd() - $readStream.Close() - } - - If ($responseBody) { - # Clear the body in case it is not a JSON (but rather html) - if ($responseBody -match "^[\s\t]*\") { $responseBody = '{"errorMessages": "Invalid server response. HTML returned."}' } - - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Retrieved body of HTTP response for more information about the error (`$responseBody)" - Write-Debug "[$($MyInvocation.MyCommand.Name)] Got the following error as `$responseBody" - try { - $result = ConvertFrom-Json -InputObject $responseBody - - } catch [ArgumentException] { # handle $responseBody being neither JSON nor HTML - $result = [PSCustomObject]@{ - errorMessages = @( - $responseBody - ) - } - } - - } - + Resolve-ErrorWebResponse -Exception $exception -StatusCode $statusCode -Cmdlet $Cmdlet } + #endregion Code 400+ + + #region Code 399- else { if ($StoreSession) { return ConvertTo-JiraSession -Session $newSessionVar -Username $Credential.UserName @@ -219,7 +189,7 @@ function Invoke-JiraMethod { $null = $PSBoundParameters.Remove("Paging") $null = $PSBoundParameters.Remove("Skip") if (-not $PSBoundParameters["GetParameter"]) { - $PSBoundParameters["GetParameter"] = $GetParameter + $PSBoundParameters["GetParameter"] = $internalGetParameter } $total = 0 @@ -298,21 +268,12 @@ function Invoke-JiraMethod { Write-Verbose "[$($MyInvocation.MyCommand.Name)] No content was returned from." } } + #endregion Code 399- } else { Write-Verbose "[$($MyInvocation.MyCommand.Name)] No Web result object was returned from. This is unusual!" } - - if ($result) { - if (Get-Member -Name "Errors","errorMessages" -InputObject $result -ErrorAction SilentlyContinue) { - Resolve-JiraError $result -WriteError -Cmdlet $Cmdlet - } - else { - Write-Output $result - } - } } - end { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended" } From 76f2156627587c4fae371a5f6d3a350bd986ca9d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 4 Jun 2018 15:36:42 +0200 Subject: [PATCH 43/83] Added paging to Get-JiraIssueComment --- JiraPS/Public/Get-JiraIssueComment.ps1 | 16 ++++++++++------ JiraPS/Public/Invoke-JiraMethod.ps1 | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/JiraPS/Public/Get-JiraIssueComment.ps1 b/JiraPS/Public/Get-JiraIssueComment.ps1 index 34e74445..49ef28b4 100644 --- a/JiraPS/Public/Get-JiraIssueComment.ps1 +++ b/JiraPS/Public/Get-JiraIssueComment.ps1 @@ -45,14 +45,18 @@ function Get-JiraIssueComment { $issueObj = Resolve-JiraIssueObject -InputObject $Issue -Credential $Credential $parameter = @{ - URI = "{0}/comment" -f $issueObj.RestURL - Method = "GET" - Credential = $Credential + URI = "{0}/comment" -f $issueObj.RestURL + Method = "GET" + GetParameter = @{ + maxResults = $PageSize + } + OutputType = "JiraComment" + Paging = $true + Credential = $Credential } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - $result = Invoke-JiraMethod @parameter - Write-Output (ConvertTo-JiraComment -InputObject $result.comments) + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter } end { diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 67695906..0236106a 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -34,7 +34,7 @@ function Invoke-JiraMethod { [Switch] $StoreSession, - [ValidateSet("JiraIssue")] + [ValidateSet("JiraIssue", "JiraComment")] [String] $OutputType, From 277daa4a30d09735fb66a3b0025f154451ec2387 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 4 Jun 2018 19:33:31 +0200 Subject: [PATCH 44/83] Added paging to Get-JiraIssueComment --- JiraPS/Public/Get-JiraGroupMember.ps1 | 97 +++++++++++---------------- JiraPS/Public/Invoke-JiraMethod.ps1 | 6 +- 2 files changed, 45 insertions(+), 58 deletions(-) diff --git a/JiraPS/Public/Get-JiraGroupMember.ps1 b/JiraPS/Public/Get-JiraGroupMember.ps1 index 8d1d7a7f..43a88d9e 100644 --- a/JiraPS/Public/Get-JiraGroupMember.ps1 +++ b/JiraPS/Public/Get-JiraGroupMember.ps1 @@ -1,5 +1,5 @@ function Get-JiraGroupMember { - [CmdletBinding()] + [CmdletBinding( SupportsPaging )] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] @@ -26,13 +26,17 @@ function Get-JiraGroupMember { [Object[]] $Group, - [ValidateRange(0, [Int]::MaxValue)] - [Int] + [Switch] + $IncludeInactive, + + [UInt32] $StartIndex = 0, - [ValidateRange(0, [Int]::MaxValue)] - [Int] - $MaxResults = 0, + [UInt32] + $MaxResults, + + [UInt32] + $PageSize = $script:DefaultPageSize, [Parameter()] [System.Management.Automation.PSCredential] @@ -43,19 +47,12 @@ function Get-JiraGroupMember { begin { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" - # This is a parameter in Get-JiraIssue, but in testing, JIRA doesn't - # reliably return more than 50 results at a time. - $pageSize = 50 + $server = Get-JiraConfigServer -ErrorAction Stop - if ($MaxResults -eq 0) { - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] MaxResults was not specified. Using loop mode to obtain all members." - $loopMode = $true - } - else { - $loopMode = $false - if ($MaxResults -gt 50) { - Write-Warning "JIRA's API may not properly support MaxResults values higher than 50 for this method. If you receive inconsistent results, do not pass the MaxResults parameter to this function to return all results." - } + $resourceURi = "$server/rest/api/latest/group/member" + + if ($PageSize -gt 50) { + Write-Warning "JIRA's API may not properly support MaxResults values higher than 50 for this method. If you receive inconsistent results, do not pass the MaxResults parameter to this function to return all results." } } @@ -69,49 +66,35 @@ function Get-JiraGroupMember { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_group]" Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_group [$_group]" - if ($loopMode) { - # Using the Size property of the group object, iterate - # through all users in a given group. - - $totalResults = $_group.Size - $allUsers = New-Object -TypeName System.Collections.ArrayList - - for ($i = 0; $i -lt $totalResults; $i = $i + $PageSize) { - if ($PageSize -gt ($i + $totalResults)) { - $thisPageSize = $totalResults - $i - } - else { - $thisPageSize = $PageSize - } - $percentComplete = ($i / $totalResults) * 100 - Write-Progress -Activity "$($MyInvocation.MyCommand.Name)" -Status "Obtaining members ($i - $($i + $thisPageSize) of $totalResults)..." -PercentComplete $percentComplete - - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Obtaining members $i - $($i + $thisPageSize)..." - $thisSection = Get-JiraGroupMember -Group $_group -StartIndex $i -MaxResults $thisPageSize -Credential $Credential - - foreach ($_user in $thisSection) { - [void] $allUsers.Add($_user) - } + $parameter = @{ + URI = $resourceURi + Method = "GET" + GetParameter = @{ + groupname = $_group.Name + maxResults = $PageSize } - - Write-Progress -Activity "$($MyInvocation.MyCommand.Name)" -Completed - Write-Output ($allUsers.ToArray()) + OutputType = "JiraUser" + Paging = $true + Credential = $Credential + } + if ($IncludeInactive) { + $parameter["includeInactiveUsers"] = $true } - else { - # Since user is an expandable property of the returned - # group from JIRA, JIRA doesn't use the MaxResults argument - # found in other REST endpoints. Instead, we need to pass - # expand=users[0:15] for users 0-15 (inclusive). - $parameter = @{ - URI = '{0}&expand=users[{1}:{2}]' -f $_group.RestUrl, $StartIndex, ($StartIndex + $MaxResults) - Method = "GET" - Credential = $Credential - } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - $result = Invoke-JiraMethod @parameter - Write-Output (ConvertTo-JiraGroup -InputObject $result).Member + # Paging + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $parameter[$_] = $PSCmdlet.PagingParameters.$_ + } + # Make `SupportsPaging` be backwards compatible + if ($StartIndex) { + $parameter["Skip"] = $StartIndex } + if ($MaxResults) { + $parameter["First"] = $MaxResults + } + + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + Invoke-JiraMethod @parameter } } diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 0236106a..1874ab87 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -34,7 +34,11 @@ function Invoke-JiraMethod { [Switch] $StoreSession, - [ValidateSet("JiraIssue", "JiraComment")] + [ValidateSet( + "JiraComment", + "JiraIssue", + "JiraUser" + )] [String] $OutputType, From e74942218225d366236c1ad67a83fc6f75f86b8d Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Mon, 4 Jun 2018 10:49:23 -0700 Subject: [PATCH 45/83] Add -Cmdlet param to Invoke-JiraMethod inside Remove-JiraIssue --- JiraPS/Public/Remove-JiraIssue.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index e4a86912..1925eae4 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -78,6 +78,7 @@ function Remove-JiraIssue { URI = $resourceURi -f $issueObj.Key,$IncludeSubTasks Method = "DELETE" Credential = $Credential + Cmdlet = $PsCmdlet } From 2e86d9ffda63b7b04abd12cac0093ea24dc152c9 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Mon, 4 Jun 2018 11:04:43 -0700 Subject: [PATCH 46/83] Fix ambiguous test description (with clarifying comments) --- Tests/Remove-JiraIssue.Tests.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Remove-JiraIssue.Tests.ps1 b/Tests/Remove-JiraIssue.Tests.ps1 index 7d30fb13..49339c4a 100644 --- a/Tests/Remove-JiraIssue.Tests.ps1 +++ b/Tests/Remove-JiraIssue.Tests.ps1 @@ -264,7 +264,9 @@ Describe "Remove-JiraIssue" { Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } - It "Throws on issues with subtasks" { + It "Writes an error on issues with subtasks" { + # Pester is not capable of (easily) asserting non-terminating errors, + # so the error is upgraded to a terminating one in this situation. { Get-JiraIssue -Key TEST-2 | Remove-JiraIssue -Force -ErrorAction Stop} | Should Throw Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } From fd602a8d11f74dd67cfae485f15df3132879cff3 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 4 Jun 2018 20:30:12 +0200 Subject: [PATCH 47/83] Added paging to Get-JiraVersion --- JiraPS/Public/Get-JiraVersion.ps1 | 47 ++++++++++++++++++++++------- JiraPS/Public/Invoke-JiraMethod.ps1 | 4 ++- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/JiraPS/Public/Get-JiraVersion.ps1 b/JiraPS/Public/Get-JiraVersion.ps1 index 088a2dd8..32708066 100644 --- a/JiraPS/Public/Get-JiraVersion.ps1 +++ b/JiraPS/Public/Get-JiraVersion.ps1 @@ -1,5 +1,5 @@ function Get-JiraVersion { - [CmdletBinding( DefaultParameterSetName = 'byId' )] + [CmdletBinding( SupportsPaging, DefaultParameterSetName = 'byId' )] param( [Parameter( Mandatory, ParameterSetName = 'byId' )] [Int[]] @@ -22,7 +22,20 @@ [Parameter( ParameterSetName = 'byInputProject' )] [Alias('Versions')] [String[]] - $Name, + $Name = "*", + + [Parameter( ParameterSetName = 'byProject')] + [Parameter( ParameterSetName = 'byInputProject')] + [ValidateSet("sequence", + "name", + "startDate", + "releaseDate" + )] + [String] + $Sort = "name", + + [UInt32] + $PageSize = $script:DefaultPageSize, [Parameter()] [System.Management.Automation.PSCredential] @@ -75,18 +88,30 @@ $projectData = Get-JiraProject -Project $_project -Credential $Credential $parameter = @{ - URI = $resourceURi -f "project/$($projectData.key)/versions" - Method = "GET" - Credential = $Credential + URI = $resourceURi -f "project/$($projectData.key)/version" + Method = "GET" + GetParameter = @{ + orderBy = $Sort + maxResults = $PageSize + } + Paging = $true + OutputType = "JiraVersion" + Credential = $Credential } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - $result = Invoke-JiraMethod @parameter - - if ($Name) { - $result = $result | Where-Object {$_.Name -in $Name} + # Paging + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $parameter[$_] = $PSCmdlet.PagingParameters.$_ } - Write-Output (ConvertTo-JiraVersion -InputObject $result) + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + # https://www.codykonior.com/2013/01/10/powershell-how-to-search-a-list-of-objects-with-an-array-of-wildcards/ + Invoke-JiraMethod @parameter | Where-Object { + $_.Name -in ( + $Name | + Select-Object @{ Name = "ExpandedItem"; Expression = { $items -like $_ }} | + Select-Object -ExpandProperty ExpandedItem -Unique + ) + } } } } diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 1874ab87..146b969b 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -37,7 +37,8 @@ function Invoke-JiraMethod { [ValidateSet( "JiraComment", "JiraIssue", - "JiraUser" + "JiraUser", + "JiraVersion" )] [String] $OutputType, @@ -47,6 +48,7 @@ function Invoke-JiraMethod { [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty, + [Parameter( DontShow )] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $Cmdlet = $PSCmdlet From 9a6825db0b96e951f92e8087d0adf8fdf1cfd842 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Mon, 4 Jun 2018 11:46:38 -0700 Subject: [PATCH 48/83] * Add separate string-based ParamSet to Remove-JiraIssue * Update Remove-JiraIssue to use [PSTypeName()] --- JiraPS/Public/Remove-JiraIssue.ps1 | 70 ++++++++++++++----------- Tests/Remove-JiraIssue.Tests.ps1 | 5 ++ docs/en-US/commands/Remove-JiraIssue.md | 44 ++++++++++++---- 3 files changed, 78 insertions(+), 41 deletions(-) diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index 1925eae4..d9bc1ee4 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -1,37 +1,37 @@ function Remove-JiraIssue { [CmdletBinding( ConfirmImpact = 'High', - SupportsShouldProcess + SupportsShouldProcess, + DefaultParameterSetName = "ByInputObject" )] param ( [Parameter( Mandatory, ValueFromPipeline, - Position = 0 + Position = 0, + 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" -ArgumentList $exception,$errorId,$errorCategory,$errorTarget - $errorItem.ErrorDetails = "Wrong object type provided for Issue. Expected [JiraPS.Issue] 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 - } - } + [Alias( + "Issue" )] + [PSTypeName("JiraPS.Issue")] [Object[]] - $Issue, + $InputObject, + + # The issue's ID number or key. + [Parameter( + Mandatory, + Position = 0, + ParameterSetName = "ByIssueId" + )] + [ValidateNotNullOrEmpty()] + [Alias( + "Id", + "Key", + "issueIdOrKey" + )] + [String[]] + $IssueId, [Switch] [Alias("deleteSubtasks")] @@ -64,18 +64,26 @@ function Remove-JiraIssue { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" - foreach ($_issue in $Issue) { - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" - Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_issue [$_issue]" + switch ($PsCmdlet.ParameterSetName) { + "ByInputObject" { $PrimaryIterator = $InputObject } + "ByIssueId" { $PrimaryIterator = $IssueID } + } - if (("JiraPS.Issue" -notin $_issue.PSObject.TypeNames)) { - $issueObj = Get-JiraIssue -Key $_issue -Credential $Credential -ErrorAction Stop + foreach ($issueItem in $PrimaryIterator) { + + if ($PsCmdlet.ParameterSetName -eq "ByIssueId") { + $_issue = Get-JiraIssue -Key $issueItem -Credential $Credential -ErrorAction Stop } Else { - $issueObj = $_issue + $_issue = $issueItem } + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_issue]" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$issueItem [$_issue]" + + + $parameter = @{ - URI = $resourceURi -f $issueObj.Key,$IncludeSubTasks + URI = $resourceURi -f $_issue.Key,$IncludeSubTasks Method = "DELETE" Credential = $Credential Cmdlet = $PsCmdlet @@ -88,7 +96,7 @@ function Remove-JiraIssue { $ActionText = "Remove issue" } - if ($PSCmdlet.ShouldProcess($issueObj.ToString(), $ActionText)) { + if ($PSCmdlet.ShouldProcess($_issue.ToString(), $ActionText)) { Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" Invoke-JiraMethod @parameter diff --git a/Tests/Remove-JiraIssue.Tests.ps1 b/Tests/Remove-JiraIssue.Tests.ps1 index 49339c4a..5b3ce213 100644 --- a/Tests/Remove-JiraIssue.Tests.ps1 +++ b/Tests/Remove-JiraIssue.Tests.ps1 @@ -259,6 +259,11 @@ Describe "Remove-JiraIssue" { Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } + It "Accepts string-based input as a non-pipelined parameter" { + {Remove-JiraIssue -IssueId TEST-2 -Force} | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It + } + It "Accepts a JiraPS.Issue object over the pipeline" { { Get-JiraIssue -Key TEST-1 | Remove-JiraIssue -Force} | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It diff --git a/docs/en-US/commands/Remove-JiraIssue.md b/docs/en-US/commands/Remove-JiraIssue.md index 48ebaf23..0a33736c 100644 --- a/docs/en-US/commands/Remove-JiraIssue.md +++ b/docs/en-US/commands/Remove-JiraIssue.md @@ -16,8 +16,17 @@ Removes an existing issue from JIRA. ## SYNTAX +### ByInputObject (Default) + +```powershell +Remove-JiraIssue [-InputObject] [-IncludeSubTasks] [[-Credential] ] [-Force] [-WhatIf] + [-Confirm] [] +``` + +### ByIssueId + ```powershell -Remove-JiraIssue [-Issue] [-IncludeSubTasks] [[-Credential] ] [-Force] [-WhatIf] +Remove-JiraIssue [-IssueId] [-IncludeSubTasks] [[-Credential] ] [-Force] [-WhatIf] [-Confirm] [] ``` @@ -35,7 +44,7 @@ If an issue includes sub-tasks, these are deleted as well. ### EXAMPLE 1 ```powershell -Remove-JiraUser -Issue ABC-123 +Remove-JiraIssue -IssueId ABC-123 ``` Removes issue \[ABC-123\] from JIRA. @@ -43,7 +52,7 @@ Removes issue \[ABC-123\] from JIRA. ### EXAMPLE 2 ```powershell -Remove-JiraUser -Issue ABC-124 -IncludeSubTasks +Remove-JiraIssue -IssueId ABC-124 -IncludeSubTasks ``` Removes issue \[ABC-124\] from JIRA, including any subtasks therein. @@ -51,24 +60,39 @@ Removes issue \[ABC-124\] from JIRA, including any subtasks therein. ### EXAMPLE 3 ```powershell -Get-JiraIssue -Query "Project = ABC AND label = NeedsDeletion" | Remove-JiraUser -IncludeSubTasks +Get-JiraIssue -Query "Project = ABC AND label = NeedsDeletion" | Remove-JiraIssue -IncludeSubTasks ``` Removes all issues from project ABC (including their subtasks) that have the label "NeedsDeletion". ## PARAMETERS -### -Issue +### -InputObject + +One or more issues to delete, specified as `JiraPS.Issue` objects (e.g. from `Get-JiraIssue`) + +```yaml +Type: Object[] +Parameter Sets: ByInputObject +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -IssueId -One or more issues to delete. These can be specified as: +One or more issues to delete, either: -* Issue key(s) (e.g. `[ABC-123]`) -* Numerical ID(s) -* Object(s) to delete (such as ones returned from `Get-JiraIssue`) +* Issue Keys (e.g. "TEST-1234") +* Numerical issue IDs ```yaml Type: Object[] -Parameter Sets: (All) +Parameter Sets: ByInputObject Aliases: Required: True From b3d1ab192302f189e4808a4fc860245533e0219f Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Mon, 4 Jun 2018 12:49:41 -0700 Subject: [PATCH 49/83] Fix inconsistencies in documentation/sanity-check tests --- docs/en-US/commands/Remove-JiraIssue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en-US/commands/Remove-JiraIssue.md b/docs/en-US/commands/Remove-JiraIssue.md index 0a33736c..f4e3c64e 100644 --- a/docs/en-US/commands/Remove-JiraIssue.md +++ b/docs/en-US/commands/Remove-JiraIssue.md @@ -91,7 +91,7 @@ One or more issues to delete, either: * Numerical issue IDs ```yaml -Type: Object[] +Type: String[] Parameter Sets: ByInputObject Aliases: From 167a1ed0bc7a04ad66f1689a31ba9cdd8d7ef061 Mon Sep 17 00:00:00 2001 From: "Sean R. Williams" Date: Mon, 4 Jun 2018 13:17:16 -0700 Subject: [PATCH 50/83] Fix broken tests --- Tests/Remove-JiraIssue.Tests.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tests/Remove-JiraIssue.Tests.ps1 b/Tests/Remove-JiraIssue.Tests.ps1 index 5b3ce213..b17143a3 100644 --- a/Tests/Remove-JiraIssue.Tests.ps1 +++ b/Tests/Remove-JiraIssue.Tests.ps1 @@ -244,7 +244,8 @@ Describe "Remove-JiraIssue" { Context "Sanity checking" { $command = Get-Command -Name Remove-JiraIssue - defParam $command 'Issue' + defParam $command 'IssueId' + defParam $command 'InputObject' defParam $command 'IncludeSubTasks' defParam $command 'Credential' } @@ -260,7 +261,7 @@ Describe "Remove-JiraIssue" { } It "Accepts string-based input as a non-pipelined parameter" { - {Remove-JiraIssue -IssueId TEST-2 -Force} | Should Not Throw + {Remove-JiraIssue -IssueId TEST-1 -Force} | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It } @@ -282,7 +283,7 @@ Describe "Remove-JiraIssue" { } It "Validates pipeline input" { - { @{id = 1} | Remove-JiraIssue -ErrorAction SilentlyContinue } | Should Throw + { @{id = 1} | Remove-JiraIssue -ErrorAction Stop} | Should Throw } } } From b4170b154393cc6d4825d8d63977e5f523e000c8 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 09:26:52 +0200 Subject: [PATCH 51/83] Updated Documentation and Tests of Paging * Added messages for deprecated parameter * Added missing parameter descriptions (including implicit parameters) * Changed parameter types to UInts * Fixed filtering of Get-Filter results * Added tests for new paging parameters --- JiraPS/Public/Get-JiraGroupMember.ps1 | 2 + JiraPS/Public/Get-JiraIssue.ps1 | 6 +- JiraPS/Public/Get-JiraVersion.ps1 | 12 +- Tests/Get-JiraGroupMember.Tests.ps1 | 185 ++++++------ Tests/Get-JiraIssue.Tests.ps1 | 97 +++++- Tests/Get-JiraIssueComment.Tests.ps1 | 11 +- Tests/Get-JiraVersion.Tests.ps1 | 332 +++++++++++++++++++-- Tests/Invoke-JiraMethod.Tests.ps1 | 4 + docs/en-US/commands/Get-JiraGroupMember.md | 104 ++++++- docs/en-US/commands/Get-JiraIssue.md | 78 ++++- docs/en-US/commands/Get-JiraVersion.md | 109 ++++++- docs/en-US/commands/Invoke-JiraMethod.md | 120 +++++++- 12 files changed, 902 insertions(+), 158 deletions(-) diff --git a/JiraPS/Public/Get-JiraGroupMember.ps1 b/JiraPS/Public/Get-JiraGroupMember.ps1 index 43a88d9e..aad482ba 100644 --- a/JiraPS/Public/Get-JiraGroupMember.ps1 +++ b/JiraPS/Public/Get-JiraGroupMember.ps1 @@ -87,9 +87,11 @@ function Get-JiraGroupMember { } # 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 } diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 3361d3f2..2bc98c8f 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -66,17 +66,17 @@ function Get-JiraIssue { [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] - [Int] + [UInt32] $StartIndex = 0, [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] - [Int] + [UInt32] $MaxResults = 0, [Parameter( ParameterSetName = 'ByJQL' )] [Parameter( ParameterSetName = 'ByFilter' )] - [Int] + [UInt32] $PageSize = $script:DefaultPageSize, [Parameter()] diff --git a/JiraPS/Public/Get-JiraVersion.ps1 b/JiraPS/Public/Get-JiraVersion.ps1 index 32708066..ecdce242 100644 --- a/JiraPS/Public/Get-JiraVersion.ps1 +++ b/JiraPS/Public/Get-JiraVersion.ps1 @@ -104,13 +104,13 @@ } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - # https://www.codykonior.com/2013/01/10/powershell-how-to-search-a-list-of-objects-with-an-array-of-wildcards/ Invoke-JiraMethod @parameter | Where-Object { - $_.Name -in ( - $Name | - Select-Object @{ Name = "ExpandedItem"; Expression = { $items -like $_ }} | - Select-Object -ExpandProperty ExpandedItem -Unique - ) + $__ = $_ + Write-Verbose ($__ | out-string) + $Name | Foreach-Object { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Matching $_ against $($__)" + $__ -like $_ + } } } } diff --git a/Tests/Get-JiraGroupMember.Tests.ps1 b/Tests/Get-JiraGroupMember.Tests.ps1 index 825baa9c..08f24ffc 100644 --- a/Tests/Get-JiraGroupMember.Tests.ps1 +++ b/Tests/Get-JiraGroupMember.Tests.ps1 @@ -6,26 +6,17 @@ . "$PSScriptRoot/Shared.ps1" - Mock Get-JiraConfigServer { + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { 'https://jira.example.com' } - # If we don't override this in a context or test, we don't want it to - # actually try to query a JIRA instance - Mock Invoke-JiraMethod { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - throw "Unidentified call to Invoke-JiraMethod" - } - - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group?groupname=testgroup*' } { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json @' -{ - "Name": "testgroup", - "RestUrl": "https://jira.example.com/rest/api/2/group?groupname=testgroup", - "Size": 2 -} -'@ + Mock Get-JiraUser -ModuleName JiraPS { + $object = [PSCustomObject] @{ + 'Name' = 'username' + } + $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') + return $object } Mock Get-JiraGroup -ModuleName JiraPS { @@ -38,104 +29,132 @@ Write-Output $obj } + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group/member' -and $GetParameter["groupname"] -eq "testgroup" } { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + ConvertFrom-Json @' +{ +"Name": "testgroup", +"RestUrl": "https://jira.example.com/rest/api/2/group?groupname=testgroup", +"Size": 2 +} +'@ + } + + # If we don't override this in a context or test, we don't want it to + # actually try to query a JIRA instance + Mock Invoke-JiraMethod { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + Context "Sanity checking" { $command = Get-Command -Name Get-JiraGroupMember defParam $command 'Group' + defParam $command 'IncludeInactive' defParam $command 'StartIndex' defParam $command 'MaxResults' defParam $command 'Credential' } Context "Behavior testing" { - Mock Invoke-JiraMethod -ModuleName JiraPS { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - } - - Mock Get-JiraUser -ModuleName JiraPS { - $object = [PSCustomObject] @{ - 'Name' = 'username' - } - $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') - return $object - } It "Obtains members about a provided group in JIRA" { { Get-JiraGroupMember -Group testgroup } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group?groupname=testgroup&expand=users*' } - } - It "Supports the -StartIndex and -MaxResults parameters to page through search results" { - { Get-JiraGroupMember -Group testgroup -StartIndex 10 -MaxResults 50 } | Should Not Throw - # Expected: expand=users[10:60] (start index of 10, last index of 10+50) - # https://docs.atlassian.com/jira/REST/6.4.12/#d2e2307 - # Also, -like doesn't seem to "like" square brackets - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group?groupname=testgroup&expand=users*10:60*' } + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/group/member' + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } - It "Returns all issues via looping if -MaxResults is not specified" { - - # In order to test this, we'll need a slightly more elaborate - # mock that actually returns some data. - - Mock Invoke-JiraMethod -ModuleName JiraPS { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json -InputObject @' -{ - "name": "testgroup", - "self": "https://jira.example.com/rest/api/2/group?groupname=testgroup", - "users": { - "size": 2, - "items": [ - { - "self": "https://jira.example.com/rest/api/2/user?username=testuser1", - "key": "testuser1", - "name": "testuser1", - "emailAddress": "testuser1@example.com", - "displayName": "Test User 1", - "active": true - }, - { - "self": "https://jira.example.com/rest/api/2/user?username=testuser2", - "key": "testuser2", - "name": "testuser2", - "emailAddress": "testuser2@example.com", - "displayName": "Test User 2", - "active": true - } - ], - "max-results": 50, - "start-index": 0, - "end-index": 0 - }, - "expand": "users" -} -'@ + It "Supports the -StartIndex parameters to page through search results" { + { Get-JiraGroupMember -Group testgroup -StartIndex 10 } | Should Not Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/group/member' -and + $PSCmdlet.PagingParameters.Skip -eq 10 + } + Scope = 'It' + Exactly = $true + Times = 1 } + Assert-MockCalled @assertMockCalledSplat + } - { Get-JiraGroupMember -Group testgroup } | Should Not Throw - - Assert-MockCalled -CommandName Get-JiraGroup -Exactly -Times 1 -Scope It -ParameterFilter { $GroupName -eq 'testgroup' } - Assert-MockCalled -CommandName Invoke-JiraMethod -Exactly -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group?groupname=testgroup&expand=users*0:2*' } - + It "Supports the -MaxResults parameters to page through search results" { + { Get-JiraGroupMember -Group testgroup -MaxResults 50 } | Should Not Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/group/member' -and + $PSCmdlet.PagingParameters.First -eq 50 + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } } Context "Input testing" { It "Accepts a group name for the -Group parameter" { { Get-JiraGroupMember -Group testgroup } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group?groupname=testgroup&expand=users*' } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/group/member' -and + $GetParameter["groupname"] -eq "testgroup" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } It "Accepts a group object for the -InputObject parameter" { $group = Get-JiraGroup -GroupName testgroup { Get-JiraGroupMember -Group $group } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/group?groupname=testgroup&expand=users*' } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/group/member' -and + $GetParameter["groupname"] -eq "testgroup" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat # We called Get-JiraGroup once manually, and it should be - # called twice by Get-JiraGroupMember. - Assert-MockCalled -CommandName Get-JiraGroup -Exactly -Times 3 -Scope It + # called once by Get-JiraGroupMember. + Assert-MockCalled -CommandName Get-JiraGroup -Exactly -Times 2 -Scope It } } } diff --git a/Tests/Get-JiraIssue.Tests.ps1 b/Tests/Get-JiraIssue.Tests.ps1 index 89cd5bdc..8ecd54fc 100644 --- a/Tests/Get-JiraIssue.Tests.ps1 +++ b/Tests/Get-JiraIssue.Tests.ps1 @@ -27,6 +27,7 @@ } '@ + #region Mocks Mock Get-JiraConfigServer { $jiraServer } @@ -36,7 +37,7 @@ ConvertFrom-Json $response } - Mock Invoke-JiraMethod -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/search?jql=$jqlEscaped*" } { + Mock Invoke-JiraMethod -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/search" -and $GetParameter["jql"] -eq $jqlEscaped } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $response } @@ -53,6 +54,7 @@ $object.PSObject.TypeNames.Insert(0, 'JiraPS.User') return $object } + #endregion Mocks Context "Sanity checking" { $command = Get-Command -Name Get-JiraIssue @@ -71,34 +73,95 @@ It "Obtains information about a provided issue in JIRA" { { Get-JiraIssue -Key TEST-001 } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/TEST-001*' } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/issue/TEST-001*' + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } It "Uses JQL to search for issues if the -Query parameter is used" { { Get-JiraIssue -Query $jql } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like "*/rest/api/latest/search?jql=$jqlEscaped*" } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/search" -and + $GetParameter["jql"] -eq $jqlEscaped + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } It "Supports the -StartIndex and -MaxResults parameters to page through search results" { { Get-JiraIssue -Query $jql -StartIndex 10 -MaxResults 50 } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like "*/rest/api/latest/search?jql=$jqlEscaped*startAt=10&maxResults=50*" } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/search" -and + $GetParameter["jql"] -eq $jqlEscaped -and + $PSCmdlet.PagingParameters.Skip -eq 10 + $PSCmdlet.PagingParameters.First -eq 50 + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } It "Returns all issues via looping if -MaxResults is not specified" { { Get-JiraIssue -Query $jql -PageSize 25 } | Should Not Throw - # This should call Invoke-JiraMethod once for one issue (to get the MaxResults value)... - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like "*/rest/api/latest/search?jql=$jqlEscaped*maxResults=1*" } - - # ...and once more with the MaxResults set to the PageSize parameter - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like "*/rest/api/latest/search?jql=$jqlEscaped*startAt=0&maxResults=25" } + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/search" -and + $GetParameter["jql"] -eq $jqlEscaped -and + $GetParameter["maxResults"] -eq 25 + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } } Context "Input testing" { It "Accepts an issue key for the -Key parameter" { { Get-JiraIssue -Key TEST-001 } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/TEST-001*' } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/issue/TEST-001*" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } It "Accepts an issue object for the -InputObject parameter" { @@ -110,7 +173,19 @@ # Should call Get-JiraIssue using the -Key parameter, so our URL should reflect the key we provided { Get-JiraIssue -InputObject $Issue } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Times 1 -Scope It -ParameterFilter { $Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/TEST-001*' } + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/issue/TEST-001*" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } } } diff --git a/Tests/Get-JiraIssueComment.Tests.ps1 b/Tests/Get-JiraIssueComment.Tests.ps1 index edcfa074..471af529 100644 --- a/Tests/Get-JiraIssueComment.Tests.ps1 +++ b/Tests/Get-JiraIssueComment.Tests.ps1 @@ -31,6 +31,8 @@ Describe "Get-JiraIssueComment" { ] } "@ + + #region Mocks Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } @@ -52,7 +54,7 @@ Describe "Get-JiraIssueComment" { # Obtaining comments from an issue...this is IT-3676 in the test environment Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -eq "$jiraServer/rest/api/latest/issue/$issueID/comment"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json -InputObject $restResult + (ConvertFrom-Json -InputObject $restResult).comments } # Generic catch-all. This will throw an exception if we forgot to mock something. @@ -60,6 +62,7 @@ Describe "Get-JiraIssueComment" { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } + #endregion Mocks ############# # Tests @@ -67,11 +70,11 @@ Describe "Get-JiraIssueComment" { It "Obtains all Jira comments from a Jira issue if the issue key is provided" { $comments = Get-JiraIssueComment -Issue $issueKey + $comments | Should Not BeNullOrEmpty @($comments).Count | Should Be 1 $comments.ID | Should Be 90730 $comments.Body | Should Be 'Test comment' - $comments.RestUrl | Should Be "$jiraServer/rest/api/2/issue/$issueID/comment/90730" # Get-JiraIssue should be called to identify the -Issue parameter Assert-MockCalled -CommandName Get-JiraIssue -ModuleName JiraPS -Exactly -Times 1 -Scope It @@ -84,15 +87,19 @@ Describe "Get-JiraIssueComment" { It "Obtains all Jira comments from a Jira issue if the Jira object is provided" { $issue = Get-JiraIssue -Key $issueKey $comments = Get-JiraIssueComment -Issue $issue + $comments | Should Not BeNullOrEmpty $comments.ID | Should Be 90730 + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } It "Handles pipeline input from Get-JiraIssue" { $comments = Get-JiraIssue -Key $issueKey | Get-JiraIssueComment + $comments | Should Not BeNullOrEmpty $comments.ID | Should Be 90730 + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It } } diff --git a/Tests/Get-JiraVersion.Tests.ps1 b/Tests/Get-JiraVersion.Tests.ps1 index 6816dc56..ea38511d 100644 --- a/Tests/Get-JiraVersion.Tests.ps1 +++ b/Tests/Get-JiraVersion.Tests.ps1 @@ -73,8 +73,8 @@ Describe "Get-JiraVersion" { { "self" : "$jiraServer/rest/api/latest/version/$versionID3", "id" : $versionID3, - "description" : "$versionName2", - "name" : "$versionName2", + "description" : "$versionName3", + "name" : "$versionName3", "archived" : "False", "released" : "False", "projectId" : "$projectId" @@ -82,7 +82,7 @@ Describe "Get-JiraVersion" { } "@ - #region Mock + #region Mocks Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } @@ -109,17 +109,17 @@ Describe "Get-JiraVersion" { ConvertFrom-Json $testJson1 } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/version/$versionId2" } { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/version/$versionId2" } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $testJson2 } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/version" } { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/version" } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $testJsonAll } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/project/*/versions" } { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/project/*/version" } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' ConvertFrom-Json $testJson1 } @@ -129,7 +129,7 @@ Describe "Get-JiraVersion" { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } - #endregion Mock + #endregion Mocks Context "Sanity checking" { $command = Get-Command -Name Get-JiraVersion @@ -141,64 +141,338 @@ Describe "Get-JiraVersion" { } Context "Behavior checking" { + It "gets a Version using Id Parameter Set" { $results = Get-JiraVersion -Id $versionID1 + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/version/$versionID1" } - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 1 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/version/$versionID1" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat } + It "gets a Version using multiple IDs" { $results = Get-JiraVersion -Id $versionID1, $versionID2 + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/version/$versionID1" } - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/version/$versionID2" } - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 2 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/version/$versionID1" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/version/$versionID2" + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 2 + } + Assert-MockCalled @assertMockCalledSplat } + It "gets a Version using the pipeline from another Version" { $version1 = ConvertTo-JiraVersion ([PSCustomObject]@{Id = [int]($versionID2)}) $version2 = ConvertTo-JiraVersion ([PSCustomObject]@{Id = [int]($versionID2); project = "lorem"}) + $results1 = ($version1 | Get-JiraVersion) $results2 = ($version1 | Get-JiraVersion) $results1 | Should Not BeNullOrEmpty $results2 | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 2 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/version/$versionID2" } - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 4 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/version/$versionID2" + } + Scope = 'It' + Exactly = $true + Times = 2 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 4 + } + Assert-MockCalled @assertMockCalledSplat } + It "gets all Versions using Project Parameter Set" { $results = Get-JiraVersion -Project $projectKey + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/project/$projectKey/versions" } - Assert-MockCalled 'Get-JiraProject' -Times 1 -Scope It -ModuleName JiraPS - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 1 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/project/$projectKey/version" -and + $Paging -eq $true + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 + } + Assert-MockCalled @assertMockCalledSplat } + It "gets all Versions using Project as pipe input" { $results = Get-JiraProject -Project $projectKey | Get-JiraVersion + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/project/$projectKey/versions" } - Assert-MockCalled 'Get-JiraProject' -Times 1 -Scope It -ModuleName JiraPS - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 1 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/project/$projectKey/version"-and + $Paging -eq $true + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + # Get-JiraProject is called once in the It block + # and once in the `Get-JiraVersion` + $assertMockCalledSplat = @{ + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 2 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 + } + Assert-MockCalled @assertMockCalledSplat } + It "gets all Versions from multiple Projects" { $results = Get-JiraVersion -Project $projectKey, "foo" + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 2 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/project/*/versions" } - Assert-MockCalled 'Get-JiraProject' -Times 2 -Scope It -ModuleName JiraPS - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 2 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/project/*/version"-and + $Paging -eq $true + } + Scope = 'It' + Exactly = $true + Times = 2 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 2 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 + } + Assert-MockCalled @assertMockCalledSplat } + It "filters the Versions from a Project by Name" { $results = Get-JiraVersion -Project $projectKey -Name $versionName1 + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/project/$projectKey/versions" } - Assert-MockCalled 'Get-JiraProject' -Times 1 -Scope It -ModuleName JiraPS - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 1 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/project/*/version"-and + $Paging -eq $true + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 + } + Assert-MockCalled @assertMockCalledSplat } + It "filters the Versions from a Project by multiple Names" { $results = Get-JiraVersion -Project $projectKey -Name $versionName1, $versionName2 + $results | Should Not BeNullOrEmpty - Assert-MockCalled 'Invoke-JiraMethod' -Times 1 -Scope It -ModuleName JiraPS -Exactly -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/latest/project/$projectKey/versions" } - Assert-MockCalled 'Get-JiraProject' -Times 1 -Scope It -ModuleName JiraPS - Assert-MockCalled 'ConvertTo-JiraVersion' -Times 1 -Scope It -ModuleName JiraPS -Exactly + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like "*/rest/api/*/project/*/version"-and + $Paging -eq $true + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 + } + Assert-MockCalled @assertMockCalledSplat } + + It "Supports the -Skip parameters to page through search results" { + { Get-JiraVersion -Project $projectKey -Skip 10 } | Should Not Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/project/*/version' -and + $Paging -eq $true -and + $PSCmdlet.PagingParameters.Skip -eq 10 + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + } + + It "Supports the -First parameters to page through search results" { + { Get-JiraVersion -Project $projectKey -First 50 } | Should Not Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/project/*/version' -and + $Paging -eq $true -and + $PSCmdlet.PagingParameters.First -eq 50 + } + Scope = 'It' + Exactly = $true + Times = 1 + } + Assert-MockCalled @assertMockCalledSplat + } + It "assert VerifiableMock" { Assert-VerifiableMock } diff --git a/Tests/Invoke-JiraMethod.Tests.ps1 b/Tests/Invoke-JiraMethod.Tests.ps1 index d04bb5f9..7cf78f1a 100644 --- a/Tests/Invoke-JiraMethod.Tests.ps1 +++ b/Tests/Invoke-JiraMethod.Tests.ps1 @@ -16,8 +16,12 @@ Describe "Invoke-JiraMethod" { defParam $command 'Body' defParam $command 'RawBody' defParam $command 'Headers' + defParam $command 'GetParameter' + defParam $command 'Paging' defParam $command 'InFile' defParam $command 'OutFile' + defParam $command 'StoreSession' + defParam $command 'OutputType' defParam $command 'Credential' defParam $command 'CmdLet' diff --git a/docs/en-US/commands/Get-JiraGroupMember.md b/docs/en-US/commands/Get-JiraGroupMember.md index 2606fac4..b618d8d9 100644 --- a/docs/en-US/commands/Get-JiraGroupMember.md +++ b/docs/en-US/commands/Get-JiraGroupMember.md @@ -16,8 +16,8 @@ Returns members of a given group in JIRA ## SYNTAX ```powershell -Get-JiraGroupMember [-Group] [[-StartIndex] ] [[-MaxResults] ] - [[-Credential] ] [] +Get-JiraGroupMember [-Group] [[-IncludeInactive] ] [[-StartIndex] ] [[-MaxResults] ] + [[PageSize] ] [-IncludeTotalCount] [-Skip ] [-First ] [[-Credential] ] [] ``` ## DESCRIPTION @@ -61,14 +61,55 @@ Accept pipeline input: True (ByPropertyName, ByValue) Accept wildcard characters: False ``` +### -IncludeInactive + +Include inactive users in the results. + +By default they are not shown. + +```yaml +Type: Switch +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PageSize + +Maximum number of results to fetch per call. + +This setting can be tuned to get better performance according to the load on the server. + +> Warning: too high of a PageSize can cause a timeout on the request. + +```yaml +Type: UInt32 +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: 25 +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 user to return. This can be used to "page" through users in a large group or a slow connection. ```yaml -Type: Int32 +Type: UInt32 Parameter Sets: (All) Aliases: @@ -81,12 +122,15 @@ 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 users will be returned. ```yaml -Type: Int32 +Type: UInt32 Parameter Sets: (All) Aliases: @@ -97,6 +141,58 @@ 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. diff --git a/docs/en-US/commands/Get-JiraIssue.md b/docs/en-US/commands/Get-JiraIssue.md index e36b56f8..5a01c7c9 100644 --- a/docs/en-US/commands/Get-JiraIssue.md +++ b/docs/en-US/commands/Get-JiraIssue.md @@ -18,27 +18,29 @@ Returns information about an issue in JIRA. ### ByIssueKey (Default) ```powershell -Get-JiraIssue [-Key] [-Credential ] [] +Get-JiraIssue [-Key] [-IncludeTotalCount] [-Skip ] [-First ] + [-Credential ] [] ``` ### ByInputObject ```powershell -Get-JiraIssue [-InputObject] [-Credential ] [] +Get-JiraIssue [-InputObject] [-IncludeTotalCount] [-Skip ] [-First ] + [-Credential ] [] ``` ### ByJQL ```powershell -Get-JiraIssue -Query [-StartIndex ] [-MaxResults ] [-PageSize ] - [-Credential ] [] +Get-JiraIssue -Query [-StartIndex ] [-MaxResults ] [[PageSize] ] + [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] ``` ### ByFilter ```powershell -Get-JiraIssue -Filter [-StartIndex ] [-MaxResults ] [-PageSize ] - [-Credential ] [] +Get-JiraIssue -Filter [-StartIndex ] [-MaxResults ] [[PageSize] ] + [-IncludeTotalCount] [-Skip ] [-First ] [-Credential ] [] ``` ## DESCRIPTION @@ -173,12 +175,15 @@ 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: Int32 +Type: UInt32 Parameter Sets: ByJQL, ByFilter Aliases: @@ -191,12 +196,15 @@ 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: Int32 +Type: UInt32 Parameter Sets: ByJQL, ByFilter Aliases: @@ -218,7 +226,7 @@ but if the REST calls take a long time, try playing with different values here. ```yaml -Type: Int32 +Type: UInt32 Parameter Sets: ByJQL, ByFilter Aliases: @@ -229,6 +237,58 @@ 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. diff --git a/docs/en-US/commands/Get-JiraVersion.md b/docs/en-US/commands/Get-JiraVersion.md index 4e1759e6..2450d0e1 100644 --- a/docs/en-US/commands/Get-JiraVersion.md +++ b/docs/en-US/commands/Get-JiraVersion.md @@ -18,25 +18,31 @@ This function returns information about a JIRA Project's Version ### byId (Default) ```powershell -Get-JiraVersion -Id [-Credential ] [] +Get-JiraVersion -Id [-PageSize ] [-IncludeTotalCount] [-Skip ] + [-First ] [-Credential ] [] ``` ### byInputVersion ```powershell -Get-JiraVersion [-InputVersion] [-Credential ] [] +Get-JiraVersion [-InputVersion] [-PageSize ] [-IncludeTotalCount] + [-Skip ] [-First ] [-Credential ] [] ``` ### byProject ```powershell -Get-JiraVersion [-Project] [-Name ] [-Credential ] [] +Get-JiraVersion [-Project] [-Name ] [[-Sort] ] + [-PageSize ] [-IncludeTotalCount] [-Skip ] [-First ] + [-Credential ] [] ``` ### byInputProject ```powershell -Get-JiraVersion [-InputProject] [-Name ] [-Credential ] [] +Get-JiraVersion [-InputProject] [-Name ] [[-Sort] ] + [-PageSize ] [-IncludeTotalCount] [-Skip ] [-First ] + [-Credential ] [] ``` ## DESCRIPTION @@ -160,6 +166,101 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### Sort + +Define the order in which the versions should be sorted before returning. + +Possible values are: + +* sequence +* name +* startDate +* releaseDate + +```yaml +Type: String +Parameter Sets: byProject, byInputProject +Aliases: Versions + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PageSize + +Maximum number of results to fetch per call. + +This setting can be tuned to get better performance according to the load on the server. + +> Warning: too high of a PageSize can cause a timeout on the request. + +```yaml +Type: UInt32 +Parameter Sets: (All) +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. diff --git a/docs/en-US/commands/Invoke-JiraMethod.md b/docs/en-US/commands/Invoke-JiraMethod.md index 47b5e548..b1f4662b 100644 --- a/docs/en-US/commands/Invoke-JiraMethod.md +++ b/docs/en-US/commands/Invoke-JiraMethod.md @@ -17,8 +17,9 @@ Invoke a specific call to a Jira REST Api endpoint ```powershell Invoke-JiraMethod [-URI] [[-Method] ] [[-Body] ] [-RawBody] - [[-Headers] ] [[-InFile] ] [[-OutFile] ] [-StoreSession] - [[-Credential] ] [[-Cmdlet] ] [] + [[-Headers] ] [[-GetParameter] ] [[-Paging] ] [[-InFile] ] + [[-OutFile] ] [-StoreSession] [[-OutputType] ] [[-Credential] ] + [[-Cmdlet] ] [] ``` ## DESCRIPTION @@ -240,6 +241,40 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -GetParameter + +Key-Value pair of the Headers to be used. + +```yaml +Type: Hashtable +Parameter Sets: (All) +Aliases: + +Required: False +Position: 4 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Paging + +Use paging on the results. + +More about paging: + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: 4 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -InFile Path to a file that will be uploaded with a multipart/form-data request. @@ -252,7 +287,7 @@ Parameter Sets: (All) Aliases: Required: False -Position: 4 +Position: 5 Default value: None Accept pipeline input: False Accept wildcard characters: False @@ -270,7 +305,7 @@ Parameter Sets: (All) Aliases: Required: False -Position: 5 +Position: 6 Default value: None Accept pipeline input: False Accept wildcard characters: False @@ -286,7 +321,25 @@ Parameter Sets: (All) Aliases: Required: False -Position: Named +Position: 7 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -OutputType + +Name of the data type that is expected to be returned. + +Currently only used in combination with `-Paging` + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 8 Default value: None Accept pipeline input: False Accept wildcard characters: False @@ -305,7 +358,7 @@ Parameter Sets: (All) Aliases: Required: False -Position: 6 +Position: 9 Default value: None Accept pipeline input: False Accept wildcard characters: False @@ -321,13 +374,66 @@ Parameter Sets: (All) Aliases: Required: False -Position: 7 +Position: 10 Default value: None 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 +``` + ### 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). From 083376b78515e5a1fd0645c3845037056679625a Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 09:34:38 +0200 Subject: [PATCH 52/83] Reverted logic to upload attachments Added the logic for uploading a file back into Add-JiraIssueAttachament. This closes #248 This is continued by #284 --- JiraPS/Private/Resolve-FilePath.ps1 | 35 +++++++++++++++++++++ JiraPS/Public/Add-JiraIssueAttachment.ps1 | 37 ++++++++++++++++++----- 2 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 JiraPS/Private/Resolve-FilePath.ps1 diff --git a/JiraPS/Private/Resolve-FilePath.ps1 b/JiraPS/Private/Resolve-FilePath.ps1 new file mode 100644 index 00000000..ea89f087 --- /dev/null +++ b/JiraPS/Private/Resolve-FilePath.ps1 @@ -0,0 +1,35 @@ +function Resolve-FilePath { + <# + .SYNOPSIS + Resolve a path to it's full path + + .DESCRIPTION + Resolve relative paths and PSDrive paths to the full path + + .LINK + https://github.com/pester/Pester/blob/5796c95e4d6ff5528b8e14865e3f25e40f01bd65/Functions/TestResults.ps1#L13-L27 + #> + [CmdletBinding()] + param( + # Path to be resolved + [Parameter( Mandatory, ValueFromPipeline )] + [ValidateNotNullOrEmpty()] + [Alias("PSPath", "LiteralPath")] + [String] + $Path + ) + + process { + $folder = Split-Path -Path $Path -Parent + $file = Split-Path -Path $Path -Leaf + + if ( -not ([String]::IsNullOrEmpty($folder))) { + $folderResolved = Resolve-Path -Path $folder + } + else { + $folderResolved = Resolve-Path -Path $ExecutionContext.SessionState.Path.CurrentFileSystemLocation + } + + Join-Path -Path $folderResolved.ProviderPath -ChildPath $file + } +} diff --git a/JiraPS/Public/Add-JiraIssueAttachment.ps1 b/JiraPS/Public/Add-JiraIssueAttachment.ps1 index a298b39f..29a2e949 100644 --- a/JiraPS/Public/Add-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Add-JiraIssueAttachment.ps1 @@ -84,15 +84,38 @@ function Add-JiraIssueAttachment { # Find the proper object for the Issue $issueObj = Resolve-JiraIssueObject -InputObject $Issue -Credential $Credential - $parameter = @{ - URI = $resourceURi -f $issueObj.RestURL - Method = "POST" - Credential = $Credential - } - foreach ($file in $FilePath) { - $parameter["InFile"] = $file + $file = Resolve-FilePath -Path $file + + $enc = [System.Text.Encoding]::GetEncoding("iso-8859-1") + $boundary = [System.Guid]::NewGuid().ToString() + + $fileName = Split-Path -Path $file -Leaf + $readFile = [System.IO.File]::ReadAllBytes($file) + $fileEnc = $enc.GetString($readFile) + + $bodyLines = @' +--{0} +Content-Disposition: form-data; name="file"; filename="{1}" +Content-Type: application/octet-stream +{2} +--{0}-- +'@ -f $boundary, $fileName, $fileEnc + + $headers = @{ + 'X-Atlassian-Token' = 'nocheck' + 'Content-Type' = "multipart/form-data; boundary=`"$boundary`"" + } + + $parameter = @{ + URI = $resourceURi -f $issueObj.RestURL + Method = "POST" + Body = $bodyLines + Headers = $headers + RawBody = $true + Credential = $Credential + } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" if ($PSCmdlet.ShouldProcess($IssueObj.Key, "Adding attachment '$($fileName)'.")) { $rawResult = Invoke-JiraMethod @parameter From a0bc520ca271bf6cf1c22039c6993f18d38e798e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 09:37:40 +0200 Subject: [PATCH 53/83] Added `-Id` parameter to Remove-JiraFilter by adding the `-Id` parameter, Remove-JiraFilter is able to take an Integer over the pipeline. This enables the used to get the data from a file (or similar) --- JiraPS/Public/Remove-JiraFilter.ps1 | 14 ++++++-- Tests/Remove-JiraFilter.Tests.ps1 | 33 +++++++++++++++++-- docs/en-US/commands/Remove-JiraFilter.md | 42 ++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/JiraPS/Public/Remove-JiraFilter.ps1 b/JiraPS/Public/Remove-JiraFilter.ps1 index e5500b45..8a892bdf 100644 --- a/JiraPS/Public/Remove-JiraFilter.ps1 +++ b/JiraPS/Public/Remove-JiraFilter.ps1 @@ -1,11 +1,15 @@ function Remove-JiraFilter { - [CmdletBinding( ConfirmImpact = "Medium", SupportsShouldProcess )] + [CmdletBinding( ConfirmImpact = "Medium", SupportsShouldProcess, DefaultParameterSetName = 'ByInputObject' )] param( - [Parameter( Mandatory, ValueFromPipeline )] + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] [PSTypeName('JiraPS.Filter')] $InputObject, + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ById')] + [UInt32[]] + $Id, + [Parameter()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] @@ -20,6 +24,12 @@ function Remove-JiraFilter { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + if ($PSCmdlet.ParameterSetName -eq 'ById') { + $InputObject = foreach ($_id in $Id) { + Get-JiraFilter -Id $_id + } + } + foreach ($filter in $InputObject) { $parameter = @{ URI = $filter.RestURL diff --git a/Tests/Remove-JiraFilter.Tests.ps1 b/Tests/Remove-JiraFilter.Tests.ps1 index ba3a2323..71dc5ac2 100644 --- a/Tests/Remove-JiraFilter.Tests.ps1 +++ b/Tests/Remove-JiraFilter.Tests.ps1 @@ -96,11 +96,18 @@ Describe 'Remove-JiraFilter' { Context "Behavior testing" { Get-JiraFilter -Id 12844 - It "Invokes the Jira API to delete a filter" { + It "deletes a filter based on one or more InputObjects" { { Get-JiraFilter -Id 12844 | Remove-JiraFilter } | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Delete' -and $URI -like '*/rest/api/*/filter/12844'} } + + It "deletes a filter based on one ore more filter ids" { + { Remove-JiraFilter -Id 12844 } | Should Not Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Delete' -and $URI -like '*/rest/api/*/filter/12844'} + } } Context "Input testing" { @@ -128,8 +135,30 @@ Describe 'Remove-JiraFilter' { Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It } + It "Accepts an ID of a filter" { + { Remove-JiraFilter -Id 12345 } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "Accepts multiple IDs of filters" { + { Remove-JiraFilter -Id 12345, 12345 } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "Accepts multiple IDs of filters over the pipeline" { + { 12345, 12345 | Remove-JiraFilter } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "fails if a negative number is passed as ID" { + { Remove-JiraFilter -Id -1 } | Should Throw + } + It "fails if something other than [JiraPS.Filter] is provided" { - { "12345" | Remove-JiraFilter -ErrorAction Stop } | Should Throw + { Get-Date | Remove-JiraFilter -ErrorAction Stop } | Should Throw { Remove-JiraFilter "12345" -ErrorAction Stop} | Should Throw } } diff --git a/docs/en-US/commands/Remove-JiraFilter.md b/docs/en-US/commands/Remove-JiraFilter.md index be4fbf57..b5fbc5a2 100644 --- a/docs/en-US/commands/Remove-JiraFilter.md +++ b/docs/en-US/commands/Remove-JiraFilter.md @@ -15,8 +15,16 @@ Removes an existing filter. ## SYNTAX +### byInputObject (Default) + ```powershell -Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] [] +Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] [] +``` + +### byId (Default) + +```powershell +Remove-JiraFilter [-Id] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -59,6 +67,18 @@ Get-JiraFilter -Favorite | Remove-JiraFilter -Confirm Asks for each favorite filter confirmation to delete it. +### Example 5 + +```powershell +$listOfFilters = 1,2,3,4 +$listOfFilters | Remove-JiraFilter +``` + +Remove filters with id "1", "2", "3" and "4". + +This input allows for the ID of the filters to be stored in an array and passed to +the command. (eg: `Get-Content` from a file with the ids) + ## PARAMETERS ### -InputObject @@ -69,7 +89,25 @@ Object can be retrieved with `Get-JiraFilter` ```yaml Type: JiraPS.Filter -Parameter Sets: (All) +Parameter Sets: ByInputObject +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -Id + +Id of the filter to be deleted. + +Accepts integers over the pipeline. + +```yaml +Type: UInt32[] +Parameter Sets: ById Aliases: Required: True From 1cb87ab76c99e1995e1c24e818eb29b84de895d2 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 09:57:43 +0200 Subject: [PATCH 54/83] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 32 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 17 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..497cc3fe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +## Description + + +## Steps To Reproduce + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +## Expected behavior + + +## Screenshots + + +## Your Environment + + +> ```powershell +> Get-Module JiraPS -ListAvailable | select version +> $PSVersionTable +> ``` + +## Possible Solution + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..066b2d92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 8d83b36b351ec3dfc84b1eb860422cbacbd5ce07 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 11:04:11 +0200 Subject: [PATCH 55/83] Improved Tests * Improved integration Tests * Improved verbosity of Pester tests --- JiraPS.build.ps1 | 5 ++--- Tests/JiraPS.Integration.Tests.ps1 | 27 +++++++++------------------ 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/JiraPS.build.ps1 b/JiraPS.build.ps1 index 43ddafba..616d725c 100644 --- a/JiraPS.build.ps1 +++ b/JiraPS.build.ps1 @@ -177,6 +177,7 @@ task UpdateManifest GetNextVersion, { # Synopsis: Create a ZIP file with this build task Package GenerateRelease, { + Remove-Item "$env:BHBuildOutput\$env:BHProjectName.zip" -ErrorAction SilentlyContinue $null = Compress-Archive -Path "$env:BHBuildOutput\$env:BHProjectName" -DestinationPath "$env:BHBuildOutput\$env:BHProjectName.zip" } #endregion BuildRelease @@ -205,9 +206,7 @@ task Test Init, { OutputFormat = "NUnitXml" CodeCoverage = $codeCoverageFiles } - if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { - $parameter["Show"] = "Fails" - } + $parameter["Show"] = "Fails" $testResults = Invoke-Pester @parameter If ('AppVeyor' -eq $env:BHBuildSystem) { diff --git a/Tests/JiraPS.Integration.Tests.ps1 b/Tests/JiraPS.Integration.Tests.ps1 index 70e5efe0..0a9fafd1 100644 --- a/Tests/JiraPS.Integration.Tests.ps1 +++ b/Tests/JiraPS.Integration.Tests.ps1 @@ -61,12 +61,14 @@ InModuleScope JiraPS { } Describe 'Handling of Versions' { + $projectKey = "TV" + + $versionName1 = "TESTv1" + $versionName2 = "TESTv2" + $versionName3 = "TESTv3" + Context 'New-JiraVersion' { # ARRANGE - $projectKey = "TV" - $versionName1 = "TESTv1" - $versionName2 = "TESTv2" - $versionName3 = "TESTv3" $versionObject = [PSCustomObject]@{ Name = $versionName1 Description = "My Description" @@ -108,10 +110,6 @@ InModuleScope JiraPS { Context 'Get-JiraVersion' { # ARRANGE - $projectKey = "TV" - $versionName1 = "TESTv1" - $versionName2 = "TESTv2" - $versionName3 = "TESTv3" $versionObject = [PSCustomObject]@{ Name = $versionName1 } @@ -153,14 +151,10 @@ InModuleScope JiraPS { Context 'Set-JiraVersion' { # ARRANGE - $projectKey = "TV" $now = (Get-Date) - $versionName1 = "TESTv1" $oldVersion1 = Get-JiraVersion -Project $projectKey -Name $versionName1 $versionNewName1 = "TESTv1.1" - $versionName2 = "TESTv2" $oldVersion2 = Get-JiraVersion -Project $projectKey -Name $versionName2 - $versionName3 = "TESTv3" $oldVersion3 = Get-JiraVersion -Project $projectKey -Name $versionName3 # ACT @@ -193,15 +187,12 @@ InModuleScope JiraPS { Context 'Remove-JiraVersion' { # ARRANGE - $projectKey = "TV" $versionName1 = "TESTv1.1" - $versionId1 = Get-JiraVersion -Project $projectKey -Name $versionName1 - $versionName2 = "TESTv2" - $versionName3 = "TESTv3" + $versionObject = Get-JiraVersion -Project $projectKey -Name $versionName2 # ACT - Remove-JiraVersion -Version $versionId1 -Force -ErrorAction Stop - Get-JiraVersion -Project $projectKey -Name $versionName2, $versionName3 | Remove-JiraVersion -Force -ErrorAction Stop + Remove-JiraVersion -Version $versionObject -Force -ErrorAction Stop + Get-JiraVersion -Project $projectKey -Name $versionName1, $versionName3 | Remove-JiraVersion -Force -ErrorAction Stop # ASSERT It 'removes the versions' { From fb6fdd0d010d6a483a23ab31338f35370563ee86 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 11:04:54 +0200 Subject: [PATCH 56/83] Fixed object returned by Get-JiraRemoteLink Get-JiraRemoteLink was using the wrong function for converting the response to object --- JiraPS/Public/Get-JiraRemoteLink.ps1 | 2 +- Tests/Get-JiraRemoteLink.Tests.ps1 | 37 +++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/JiraPS/Public/Get-JiraRemoteLink.ps1 b/JiraPS/Public/Get-JiraRemoteLink.ps1 index 9761cd95..875c1b28 100644 --- a/JiraPS/Public/Get-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Get-JiraRemoteLink.ps1 @@ -64,7 +64,7 @@ function Get-JiraRemoteLink { Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" $result = Invoke-JiraMethod @parameter - Write-Output (ConvertTo-JiraIssueLinkType -InputObject $result) + Write-Output (ConvertTo-JiraLink -InputObject $result) } } diff --git a/Tests/Get-JiraRemoteLink.Tests.ps1 b/Tests/Get-JiraRemoteLink.Tests.ps1 index e2a3633d..bd5ad624 100644 --- a/Tests/Get-JiraRemoteLink.Tests.ps1 +++ b/Tests/Get-JiraRemoteLink.Tests.ps1 @@ -49,7 +49,7 @@ Describe "Get-JiraRemoteLink" { Get-JiraIssue -Key $Issue } - Mock ConvertTo-JiraIssueLinkType -ModuleName JiraPS { + Mock ConvertTo-JiraLink -ModuleName JiraPS { $InputObject } @@ -73,14 +73,45 @@ Describe "Get-JiraRemoteLink" { $getResult = Get-JiraRemoteLink -Issue $issueKey $getResult | Should Not BeNullOrEmpty - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq "Get" -and $Uri -like "$jiraServer/rest/api/*/issue/12345/remotelink"} + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq "Get" -and + $Uri -like "$jiraServer/rest/api/*/issue/12345/remotelink" + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + + $assertMockCalledSplat = @{ + CommandName = 'ConvertTo-JiraLink' + ModuleName = 'JiraPS' + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat } It "Gets information of all remote link from a Jira issue" { $getResult = Get-JiraRemoteLink -Issue $issueKey -LinkId 10000 $getResult | Should Not BeNullOrEmpty - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq "Get" -and $Uri -like "$jiraServer/rest/api/*/issue/12345/remotelink/10000"} + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq "Get" -and + $Uri -like "$jiraServer/rest/api/*/issue/12345/remotelink/10000" + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat } } } From 29363d0fa204949fc735fce4d580d6839078fcee Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 11:12:53 +0200 Subject: [PATCH 57/83] Removed AppVeyor config to skip CI --- appveyor.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index b3835125..da589401 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,13 +25,6 @@ skip_tags: true # Or if I include "skip-tests" in the commit message skip_commits: message: /skip\-tests/ - files: - - .github/ - - .vscode/ - - README.md - - .gitattributes - - .gitignore - - .env* # PRs, by definition, don't change anything and therefore should not increment the version # To be fair, this is not important, and is really just AppVeyor enabling my pedantry From 3de646983a8ab49ec18924f3276fbabde4eee4a3 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 11:25:55 +0200 Subject: [PATCH 58/83] Remove "Content-Type" from headers PSv6 will try to validate the headers - and "Content-Type" will fail --- JiraPS/Public/Invoke-JiraMethod.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 146b969b..c8acf2c2 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -113,6 +113,7 @@ function Invoke-JiraMethod { if ($_headers.ContainsKey("Content-Type")) { $splatParameters["ContentType"] = $_headers["Content-Type"] + $splatParameters["Headers"].Remove("Content-Type") $_headers.Remove("Content-Type") } From 8b25760d597777383b2b614573a057de005cc383 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 11:39:51 +0200 Subject: [PATCH 59/83] Added support for TLS1.2 in all web calls closes #283 --- JiraPS/Public/Invoke-JiraMethod.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index c8acf2c2..776179b7 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -57,6 +57,8 @@ function Invoke-JiraMethod { begin { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + Set-TlsLevel -Tls12 + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" @@ -282,6 +284,8 @@ function Invoke-JiraMethod { } } end { + Set-TlsLevel -Revert + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended" } } From 6f76a61cef9f96e84c286d45e18f44abb1caf7c9 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 14 Jun 2018 20:22:17 +0200 Subject: [PATCH 60/83] Updated documentation on Add-JiraFilterPermission * added tests (WIP) * added external help * added -Id parameterSet * changed documentation on other functions (WIP) --- JiraPS/Public/Add-JiraFilterPermission.ps1 | 40 +++--- Tests/Add-JiraFilterPermission.Tests.ps1 | 125 +++++++++++++++++ .../commands/Add-JiraFilterPermission.md | 131 ++++++++++++------ docs/en-US/commands/Remove-JiraFilter.md | 2 +- .../commands/Remove-JiraFilterPermission.md | 2 +- 5 files changed, 237 insertions(+), 63 deletions(-) create mode 100644 Tests/Add-JiraFilterPermission.Tests.ps1 diff --git a/JiraPS/Public/Add-JiraFilterPermission.ps1 b/JiraPS/Public/Add-JiraFilterPermission.ps1 index e21bbb6f..b0fa88c0 100644 --- a/JiraPS/Public/Add-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Add-JiraFilterPermission.ps1 @@ -1,37 +1,27 @@ function Add-JiraFilterPermission { - [CmdletBinding( SupportsShouldProcess )] + [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ByInputObject' )] + [OutputType( [JiraPS.FilterPermission] )] param( - # Filter object to which the permission should be applied - [Parameter( Mandatory, ValueFromPipeline )] + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] [PSTypeName('JiraPS.Filter')] $Filter, - # Type of the permission to add - [Parameter( Mandatory )] + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ById')] + [UInt32[]] + $Id, + + [Parameter( Position = 1, Mandatory )] [ValidateNotNullOrEmpty()] [ValidateSet('Group', 'Project', 'ProjectRole', 'Authenticated', 'Global')] [String]$Type, - # Value for the Type of the permission - # - # The Value differs per Type of the permission. - # Here is a table to know what Value to provide: - # - # |Type |Value |Source | - # |-------------|---------------------|----------------------------------------------------| - # |Group |Name of the Group |Can be retrieved with `(Get-JiraGroup ...).Name` | - # |Project |Id of the Project |Can be retrieved with `(Get-JiraProject ...).Id` | - # |ProjectRole |Id of the ProjectRole|Can be retrieved with `(Get-JiraProjectRole ...).Id`| - # |Authenticated| **must be null** | | - # |Global | **must be null** | | [String]$Value, - # Credentials to use to connect to JIRA. - # - # If not specified, this function will use anonymous access. - [PSCredential] - $Credential + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { @@ -44,6 +34,12 @@ Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" + if ($PSCmdlet.ParameterSetName -eq 'ById') { + $InputObject = foreach ($_id in $Id) { + Get-JiraFilter -Id $_id + } + } + $body = @{ type = $Type.ToLower() } diff --git a/Tests/Add-JiraFilterPermission.Tests.ps1 b/Tests/Add-JiraFilterPermission.Tests.ps1 new file mode 100644 index 00000000..1d56300e --- /dev/null +++ b/Tests/Add-JiraFilterPermission.Tests.ps1 @@ -0,0 +1,125 @@ +Describe 'Add-JiraFilterPermission' { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + #region Definitions + $jiraServer = "https://jira.example.com" + + $responseFilter = @" +{ + "self": "$jiraServer/rest/api/latest/filter/12844", + "id": "12844", + "name": "{0}", + "jql": "{1}", + "favourite": false +} +"@ + #endregion Definitions + + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { + $jiraServer + } + + Mock ConvertTo-JiraFilterPermission -ModuleName JiraPS { + $i = (ConvertFrom-Json $responseFilter) + $i.PSObject.TypeNames.Insert(0, 'JiraPS.FilterPermission') + $i + } + + Mock Get-JiraFilter -ModuleName JiraPS { + ConvertTo-JiraFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Post' -and $URI -like "$jiraServer/rest/api/*/filter"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'Body' + ConvertFrom-Json $responseFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + + Context "Sanity checking" { + $command = Get-Command -Name Add-JiraFilterPermission + + defParam $command 'Filter' + defParam $command 'Type' + defParam $command 'Value' + defParam $command 'Credential' + } + + Context "Behavior testing" { + It "Invokes the Jira API to create a filter" { + { + $newData = @{ + Name = "myName" + Description = "myDescription" + JQL = "myJQL" + Favorite = $true + } + New-JiraFilter @newData + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter' -and + $Body -match "`"name`":\s*`"myName`"" -and + $Body -match "`"description`":\s*`"myDescription`"" -and + $Body -match "`"jql`":\s*`"myJQL`"" -and + $Body -match "`"favourite`":\s*true" + } + } + } + + Context "Input testing" { + It "-Name and -JQL" { + { + $parameter = @{ + Name = "newName" + JQL = "newJQL" + } + New-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "-Name and -Description and -JQL" { + { + $parameter = @{ + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + } + New-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "-Name and -Description and -JQL and -Favorite" { + { + $parameter = @{ + Name = "newName" + Description = "newDescription" + JQL = "newJQL" + Favorite = $true + } + New-JiraFilter @parameter + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + It "maps the properties of an object to the parameters" { + { Get-JiraFilter "12345" | New-JiraFilter } | Should Not Throw + } + } + } +} diff --git a/docs/en-US/commands/Add-JiraFilterPermission.md b/docs/en-US/commands/Add-JiraFilterPermission.md index 4ef07c0f..ea354d97 100644 --- a/docs/en-US/commands/Add-JiraFilterPermission.md +++ b/docs/en-US/commands/Add-JiraFilterPermission.md @@ -1,68 +1,74 @@ --- external help file: JiraPS-help.xml Module Name: JiraPS -online version: +online version: https://atlassianps.org/docs/JiraPS/commands/Add-JiraFilterPermission/ +locale: en-US schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Add-JiraFilterPermission/ --- - # Add-JiraFilterPermission ## SYNOPSIS -{{Fill in the Synopsis}} + +Share a Filter with other users. ## SYNTAX +### ByInputObject (Default) + +```powershell +Add-JiraFilterPermission [-Filter] [-Type] [[-Value] ] + [[-Credential] ] [-WhatIf] [-Confirm] [] ``` -Add-JiraFilterPermission [-Filter] [-Type] [[-Value] ] [[-Credential] ] - [-WhatIf] [-Confirm] [] + +### ById + +```powershell +Add-JiraFilterPermission [-Id] [-Type] [[-Value] ] + [[-Credential] ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -{{Fill in the Description}} + +Share a Filter with other users, such as "Group", "Project", "ProjectRole", +"Authenticated" or "Global". ## EXAMPLES ### Example 1 + ```powershell -PS C:\> {{ Add example code here }} +Add-JiraFilterPermission -Filter (Get-JiraFilter 12345) -Type "Global" +#------- +Add-JiraFilterPermission -Id 12345 -Type "Global" ``` -{{ Add example description here }} - -## PARAMETERS +Two methods of sharing Filter 12345 with everyone. -### -Confirm -Prompts you for confirmation before running the cmdlet. - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: cf +### Example 2 -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False +```powershell +12345 | Add-JiraFilterPermission -Type "Authenticated" ``` -### -Credential -{{Fill Credential Description}} +Share Filter 12345 with authenticated users. -```yaml -Type: PSCredential -Parameter Sets: (All) -Aliases: +_The Id could be read from a file._ -Required: False -Position: 3 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False +### Example 3 + +```powershell +Get-JiraFilter 12345 | Add-JiraFilterPermission -Type "Group" -Value "administrators" ``` +Share Filter 12345 only with users in the administrators groups. + +## PARAMETERS + ### -Filter -{{Fill Filter Description}} + +Filter object to which the permission should be applied ```yaml Type: Object @@ -77,7 +83,8 @@ Accept wildcard characters: False ``` ### -Type -{{Fill Type Description}} + +Type of the permission to add ```yaml Type: String @@ -93,7 +100,19 @@ Accept wildcard characters: False ``` ### -Value -{{Fill Value Description}} + +Value for the Type of the permission. + +The Value differs per Type of the permission. + +Here is a table to know what Value to provide: +|Type |Value |Source | +|-------------|---------------------|----------------------------------------------------| +|Group |Name of the Group |Can be retrieved with `(Get-JiraGroup ...).Name` | +|Project |Id of the Project |Can be retrieved with `(Get-JiraProject ...).Id` | +|ProjectRole |Id of the ProjectRole|Can be retrieved with `(Get-JiraProjectRole ...).Id`| +|Authenticated| **must be null** | | +|Global | **must be null** | | ```yaml Type: String @@ -107,7 +126,25 @@ 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 +``` + ### -WhatIf + Shows what would happen if the cmdlet runs. The cmdlet is not run. @@ -123,18 +160,34 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +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 -### System.Object - +### [JiraPS.Filter] ## OUTPUTS -### System.Object +### [JiraPS.FilterPermission] ## NOTES diff --git a/docs/en-US/commands/Remove-JiraFilter.md b/docs/en-US/commands/Remove-JiraFilter.md index be4fbf57..b86af168 100644 --- a/docs/en-US/commands/Remove-JiraFilter.md +++ b/docs/en-US/commands/Remove-JiraFilter.md @@ -16,7 +16,7 @@ Removes an existing filter. ## SYNTAX ```powershell -Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] [] +Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION diff --git a/docs/en-US/commands/Remove-JiraFilterPermission.md b/docs/en-US/commands/Remove-JiraFilterPermission.md index aaf802cb..41afe8c5 100644 --- a/docs/en-US/commands/Remove-JiraFilterPermission.md +++ b/docs/en-US/commands/Remove-JiraFilterPermission.md @@ -13,7 +13,7 @@ schema: 2.0.0 ## SYNTAX ``` -Remove-JiraFilterPermission [-InputObject] [[-Credential] ] [-WhatIf] [-Confirm] +Remove-JiraFilterPermission [-InputObject] [[-Credential] ] [-WhatIf] [-Confirm] [] ``` From 82f6a631567f89a1a8e6b5a19c14db33f2d357ed Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 13:59:55 +0200 Subject: [PATCH 61/83] Implemented Remove-JiraFilterPermission --- JiraPS/Public/Remove-JiraFilterPermission.ps1 | 82 +++++++--- Tests/Remove-JiraFilterPermission.Tests.ps1 | 151 ++++++++++++++++++ .../commands/Remove-JiraFilterPermission.md | 135 ++++++++++++---- 3 files changed, 319 insertions(+), 49 deletions(-) create mode 100644 Tests/Remove-JiraFilterPermission.Tests.ps1 diff --git a/JiraPS/Public/Remove-JiraFilterPermission.ps1 b/JiraPS/Public/Remove-JiraFilterPermission.ps1 index d0313502..be5affac 100644 --- a/JiraPS/Public/Remove-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Remove-JiraFilterPermission.ps1 @@ -1,17 +1,52 @@ function Remove-JiraFilterPermission { - [CmdletBinding( SupportsShouldProcess )] + [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ByFilterId' )] param( - # Filter object to which the permission should be applied - [Parameter( Mandatory, ValueFromPipeline )] + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByFilterObject' )] [ValidateNotNullOrEmpty()] - [PSTypeName('JiraPS.FilterPermission')] - $InputObject, - - # Credentials to use to connect to JIRA. - # - # If not specified, this function will use anonymous access. - [PSCredential] - $Credential + [ValidateScript( + { + if (@($Filter).Count -gt 1) { + $exception = ([System.ArgumentException]"Invalid Parameter") + $errorId = 'ParameterType.TooManyFilters' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget + $errorItem.ErrorDetails = "Only one Filter can be passed at a time." + $PSCmdlet.ThrowTerminatingError($errorItem) + } + elseif (@($_.FilterPermissions).Count -lt 1) { + $exception = ([System.ArgumentException]"Invalid Type for Parameter") + $errorId = 'ParameterType.FilterWithoutPermission' + $errorCategory = 'InvalidArgument' + $errorTarget = $_ + $errorItem = New-Object -TypeName System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $errorTarget + $errorItem.ErrorDetails = "The Filter provided does not contain any Permission to delete." + $PSCmdlet.ThrowTerminatingError($errorItem) + } + else { + return $true + } + } + )] + [PSTypeName('JiraPS.Filter')] + $Filter, + + [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByFilterId' )] + [ValidateNotNullOrEmpty()] + [Alias('Id')] + [UInt32] + $FilterId, + + # TODO: [Parameter( Position = 1, ParameterSetName = 'ByFilterObject')] + [Parameter( Position = 1, Mandatory, ParameterSetName = 'ByFilterId')] + [ValidateNotNullOrEmpty()] + [UInt32[]] + $PermissionId, + + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { @@ -22,14 +57,25 @@ Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" - $parameter = @{ - URI = $InputObject.RestURL - Method = "DELETE" - Credential = $Credential + switch ($PSCmdlet.ParameterSetName) { + "ByFilterObject" { + $PermissionId = $Filter.FilterPermissions.Id + } + "ByFilterId" { + $Filter = Get-JiraFilter -Id $FilterId + } } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - if ($PSCmdlet.ShouldProcess($InputObject.Type, "Remove Permission")) { - Invoke-JiraMethod @parameter + + foreach ($_permissionId in $PermissionId) { + $parameter = @{ + URI = "{0}/permission/{1}" -f $Filter.RestURL, $_permissionId + Method = "DELETE" + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($InputObject.Type, "Remove Permission")) { + Invoke-JiraMethod @parameter + } } } diff --git a/Tests/Remove-JiraFilterPermission.Tests.ps1 b/Tests/Remove-JiraFilterPermission.Tests.ps1 new file mode 100644 index 00000000..8d34ed47 --- /dev/null +++ b/Tests/Remove-JiraFilterPermission.Tests.ps1 @@ -0,0 +1,151 @@ +Describe 'Remove-JiraFilterPermission' { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + #region Definitions + $jiraServer = "https://jira.example.com" + + $filterPermission1 = New-Object -TypeName PSCustomObject -Property @{ Id = 1111 } + $filterPermission1.PSObject.TypeNames.Insert(0, 'JiraPS.FilterPermission') + $filterPermission2 = New-Object -TypeName PSCustomObject -Property @{ Id = 2222 } + $filterPermission2.Id = 2222 + $fullFilter = New-Object -TypeName PSCustomObject -Property @{ + Id = 12345 + RestUrl = "$jiraServer/rest/api/2/filter/12345" + FilterPermissions = @( + $filterPermission1 + $filterPermission2 + ) + } + $fullFilter.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $basicFilter = New-Object -TypeName PSCustomObject -Property @{ + Id = 23456 + RestUrl = "$jiraServer/rest/api/2/filter/23456" + } + $basicFilter.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + + #endregion Definitions + + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { + $jiraServer + } + + Mock Get-JiraFilter -ModuleName JiraPS { + $basicFilter + } + + Mock Get-JiraFilterPermission -ModuleName JiraPS { + $fullFilter + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Delete' -and $URI -like "$jiraServer/rest/api/*/filter/*/permission*"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + } + + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + + Context "Sanity checking" { + $command = Get-Command -Name Remove-JiraFilterPermission + + defParam $command 'Filter' + defParam $command 'FilterId' + defParam $command 'PermissionId' + defParam $command 'Credential' + } + + Context "Behavior testing" { + It "Deletes Permission from Filter Object" { + { + Get-JiraFilterPermission -Id 1 | Remove-JiraFilterPermission + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Delete' -and + $URI -like '*/rest/api/*/filter/12345/permission/1111' + } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Delete' -and + $URI -like '*/rest/api/*/filter/12345/permission/2222' + } + } + + It "Deletes Permission from FilterId + PermissionId" { + { + Remove-JiraFilterPermission -FilterId 1 -PermissionId 3333, 4444 + } | Should Not Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Delete' -and + $URI -like '*/rest/api/*/filter/23456/permission/3333' + } + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Delete' -and + $URI -like '*/rest/api/*/filter/23456/permission/4444' + } + } + } + + Context "Input testing" { + It "validates the -Filter to ensure FilterPermissions" { + { Remove-JiraFilterPermission -Filter (Get-JiraFilter -Id 1) } | Should -Throw + { Remove-JiraFilterPermission -Filter (Get-JiraFilterPermission -Id 1) } | Should -Not -Throw + } + + It "finds the filter by FilterId" { + { Remove-JiraFilterPermission -FilterId 1 -PermissionId 1111 } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "does not accept negative FilterIds" { + { Remove-JiraFilterPermission -FilterId -1 -PermissionId 1111 } | Should -Throw + } + + It "does not accept negative PermissionIds" { + { Remove-JiraFilterPermission -FilterId 1 -PermissionId -1111 } | Should -Throw + } + + It "can only process one FilterId" { + { Remove-JiraFilterPermission -FilterId 1, 2 -PermissionId 1111 } | Should -Throw + } + + It "can process multiple PermissionIds" { + { Remove-JiraFilterPermission -FilterId 1 -PermissionId 1111, 2222 } | Should -Not -Throw + } + + It "allows for the filter to be passed over the pipeline" { + { Get-JiraFilterPermission -Id 1 | Remove-JiraFilterPermission } | Should -Not -Throw + } + + It "can ony process one Filter objects" { + $filter = @() + $filter += Get-JiraFilterPermission -Id 1 + $filter += Get-JiraFilterPermission -Id 1 + + { Remove-JiraFilterPermission -Filter $filter } | Should -Throw + } + + It "resolves positional parameters" { + { Remove-JiraFilterPermission 12345 1111 } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + + $filter = Get-JiraFilterPermission -Id 1 + { Remove-JiraFilterPermission $filter } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 3 -Scope It + } + } + } +} diff --git a/docs/en-US/commands/Remove-JiraFilterPermission.md b/docs/en-US/commands/Remove-JiraFilterPermission.md index 41afe8c5..f60384b7 100644 --- a/docs/en-US/commands/Remove-JiraFilterPermission.md +++ b/docs/en-US/commands/Remove-JiraFilterPermission.md @@ -1,82 +1,125 @@ --- external help file: JiraPS-help.xml Module Name: JiraPS -online version: https://atlassianps.org/docs/JiraPS/commands/New-JiraVersion/ +online version: https://atlassianps.org/docs/JiraPS/commands/Remove-JiraFilterPermission/ +locale: en-US schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Remove-JiraFilterPermission/ --- - # Remove-JiraFilterPermission ## SYNOPSIS -{{Fill in the Synopsis}} + +Remove a permission of a Filter ## SYNTAX +### ByFilterId (Default) + +```powershell +Remove-JiraFilterPermission [-Filter] [[-Credential] ] + [-WhatIf] [-Confirm] [] ``` -Remove-JiraFilterPermission [-InputObject] [[-Credential] ] [-WhatIf] [-Confirm] - [] + +### ByFilterObject + +```powershell +Remove-JiraFilterPermission [-FilterId] [-PermissionId] + [[-Credential] ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION -{{Fill in the Description}} + +Remove a sharing permission of a Filter. ## EXAMPLES ### Example 1 + +```powershell +Remove-JiraFilterPermission -FilterId 11822 -PermissionId 1111, 2222 +``` + +Remove two share permissions of Filter with ID '11822' + +### Example 1 + ```powershell -PS C:\> {{ Add example code here }} +Get-JiraFilter 11822 | Get-JiraFilterPermission | Remove-JiraFilterPermission ``` -{{ Add example description here }} +Remove all permissions of Filter 11822 ## PARAMETERS -### -Confirm -Prompts you for confirmation before running the cmdlet. +### -Filter + +Object of the Filter from which to remove a permission. ```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: cf +Type: JiraPS.Filter +Parameter Sets: ByFilterObject +Aliases: -Required: False -Position: Named +Required: True +Position: 0 Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` -### -Credential -{{Fill Credential Description}} +### -FilterId + +Id of the Filter from which to remove a permission. ```yaml -Type: PSCredential -Parameter Sets: (All) +Type: UInt32 +Parameter Sets: ByFilterId Aliases: -Required: False -Position: 1 +Required: True +Position: 0 Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` -### -InputObject -{{Fill InputObject Description}} +### -PermissionId + +List of id's of the permissions to remove. ```yaml -Type: Object -Parameter Sets: (All) +Type: UInt32[] +Parameter Sets: ByFilterId Aliases: Required: True -Position: 0 +Position: 1 Default value: None Accept pipeline input: True (ByValue) 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: 1 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -WhatIf + Shows what would happen if the cmdlet runs. The cmdlet is not run. @@ -92,19 +135,49 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +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). + +This cmdlet supports the common parameters: -Debug, -ErrorAction, +-ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, +-OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters +(). ## INPUTS ### System.Object - ## OUTPUTS ### System.Object ## 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-JiraFilter](../Get-JiraFilter/) + +[Add-JiraFilterPermission](../Add-JiraFilterPermission/) + +[Get-JiraFilterPermission](../Get-JiraFilterPermission/) From 9283dbc5c3ccf17d69abc305bb3801707e363995 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 14:00:58 +0200 Subject: [PATCH 62/83] Improved implementation of Get-JiraFilterPermission added Unit tests --- JiraPS/Public/Get-JiraFilterPermission.ps1 | 40 +++--- Tests/Get-JiraFilterPermission.Tests.ps1 | 125 ++++++++++++++++++ .../commands/Get-JiraFilterPermission.md | 108 +++++++++++---- 3 files changed, 235 insertions(+), 38 deletions(-) create mode 100644 Tests/Get-JiraFilterPermission.Tests.ps1 diff --git a/JiraPS/Public/Get-JiraFilterPermission.ps1 b/JiraPS/Public/Get-JiraFilterPermission.ps1 index 8c3a992a..bc8fc4f6 100644 --- a/JiraPS/Public/Get-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Get-JiraFilterPermission.ps1 @@ -1,17 +1,21 @@ function Get-JiraFilterPermission { - [CmdletBinding()] + [CmdletBinding( DefaultParameterSetName = 'ById' )] + # [OutputType( [JiraPS.FilterPermission] )] param( - # Filter object from which to retrieve the permissions - [Parameter( Mandatory, ValueFromPipeline )] + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] [PSTypeName('JiraPS.Filter')] $Filter, - # Credentials to use to connect to JIRA. - # - # If not specified, this function will use anonymous access. - [PSCredential] - $Credential + [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ById')] + [ValidateNotNullOrEmpty()] + [UInt32[]] + $Id, + + [Parameter()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { @@ -24,15 +28,21 @@ function Get-JiraFilterPermission { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" - $parameter = @{ - URI = $resourceURi -f $Filter.RestURL - Method = "GET" - Credential = $Credential + if ($PSCmdlet.ParameterSetName -eq 'ById') { + $Filter = Get-JiraFilter -Id $Id } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - $result = Invoke-JiraMethod @parameter - Write-Output (ConvertTo-JiraFilterPermission -InputObject $result) + foreach ($_filter in $Filter) { + $parameter = @{ + URI = $resourceURi -f $_filter.RestURL + Method = "GET" + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + $result = Invoke-JiraMethod @parameter + + Write-Output (ConvertTo-JiraFilter -InputObject $_filter -FilterPermissions $result) + } } end { diff --git a/Tests/Get-JiraFilterPermission.Tests.ps1 b/Tests/Get-JiraFilterPermission.Tests.ps1 new file mode 100644 index 00000000..71ff2533 --- /dev/null +++ b/Tests/Get-JiraFilterPermission.Tests.ps1 @@ -0,0 +1,125 @@ +Describe 'Get-JiraFilterPermission' { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + #region Definitions + $jiraServer = "https://jira.example.com" + + $sampleResponse = @" +{ + "id": 10000, + "type": "global" +} +"@ + #endregion Definitions + + #region Mocks + Mock Get-JiraConfigServer -ModuleName JiraPS { + $jiraServer + } + + Mock ConvertTo-JiraFilter -ModuleName JiraPS { } + + Mock Get-JiraFilter -ModuleName JiraPS { + foreach ($_id in $Id) { + $basicFilter = New-Object -TypeName PSCustomObject -Property @{ + Id = $Id + RestUrl = "$jiraServer/rest/api/2/filter/$Id" + } + $basicFilter.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $basicFilter + } + } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/filter/*/permission"} { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + ConvertFrom-Json $sampleResponse + } + + Mock Invoke-JiraMethod -ModuleName JiraPS { + ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' + throw "Unidentified call to Invoke-JiraMethod" + } + #endregion Mocks + + Context "Sanity checking" { + $command = Get-Command -Name Get-JiraFilterPermission + + defParam $command 'Filter' + defParam $command 'Id' + defParam $command 'Credential' + } + + Context "Behavior testing" { + It "Retrieves the permissions of a Filter by Object" { + { Get-JiraFilter -Id 23456 | Get-JiraFilterPermission } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/filter/23456/permission' + } + } + + It "Retrieves the permissions of a Filter by Id" { + { 23456 | Get-JiraFilterPermission } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Get' -and + $URI -like '*/rest/api/*/filter/23456/permission' + } + } + } + + Context "Input testing" { + It "finds the filter by Id" { + { Get-JiraFilterPermission -Id 23456 } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "does not accept negative Ids" { + { Get-JiraFilterPermission -Id -1 } | Should -Throw + } + + It "can process multiple Ids" { + { Get-JiraFilterPermission -Id 23456, 23456 } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "allows for the filter to be passed over the pipeline" { + { Get-JiraFilter -Id 23456 | Get-JiraFilterPermission } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "can ony process one Filter objects" { + $filter = @() + $filter += Get-JiraFilter -Id 23456 + $filter += Get-JiraFilter -Id 23456 + + { Get-JiraFilterPermission -Filter $filter } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "resolves positional parameters" { + { Get-JiraFilterPermission 23456 } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + + $filter = Get-JiraFilter -Id 23456 + { Get-JiraFilterPermission $filter } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + } + } +} diff --git a/docs/en-US/commands/Get-JiraFilterPermission.md b/docs/en-US/commands/Get-JiraFilterPermission.md index 98eb689e..b9878f71 100644 --- a/docs/en-US/commands/Get-JiraFilterPermission.md +++ b/docs/en-US/commands/Get-JiraFilterPermission.md @@ -1,56 +1,87 @@ --- external help file: JiraPS-help.xml Module Name: JiraPS -online version: https://atlassianps.org/docs/JiraPS/commands/Get-JiraFilter/ +online version: https://atlassianps.org/docs/JiraPS/commands/Get-JiraFilterPermission/ +locale: en-US schema: 2.0.0 +layout: documentation +permalink: /docs/JiraPS/commands/Get-JiraFilterPermission/ --- - # Get-JiraFilterPermission ## SYNOPSIS -{{Fill in the Synopsis}} + +Fetch the permissions of a specific Filter. ## SYNTAX +### ByInputObject (Default) + +```powershell +Get-JiraFilterPermission [-Filter] [[-Credential] ] + [] ``` -Get-JiraFilterPermission [-Filter] [[-Credential] ] [] + +### ById + +```powershell +Get-JiraFilterPermission [-Id] [[-Credential] ] + [] ``` ## DESCRIPTION -{{Fill in the Description}} + +This allows the user to retrieve all the sharing permissions set for a Filter. ## EXAMPLES ### Example 1 + ```powershell -PS C:\> {{ Add example code here }} +Get-JiraFilterPermission -Filter (Get-JiraFilter 12345) +#------- +Get-JiraFilterPermission -Id 12345 ``` -{{ Add example description here }} +Two methods for retrieving the permissions set for Filter 12345. + +### Example 2 + +```powershell +12345 | Get-JiraFilterPermission +#------- +Get-JiraFilter 12345 | Add-JiraFilterPermission +``` + +Two methods for retrieve the permissions set for Filter 12345 by using the pipeline. + +_The Id could be read from a file._ ## PARAMETERS -### -Credential -{{Fill Credential Description}} +### -Filter + +Filter object from which to retrieve the permissions ```yaml -Type: PSCredential -Parameter Sets: (All) +Type: JiraPS.Filter +Parameter Sets: ByInputObject Aliases: -Required: False -Position: 1 +Required: True +Position: 0 Default value: None -Accept pipeline input: False +Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` -### -Filter -{{Fill Filter Description}} +### -Id + +Id of the Filter from which to retrieve the permissions ```yaml -Type: Object -Parameter Sets: (All) +Type: UInt32[] +Parameter Sets: ById Aliases: Required: True @@ -60,19 +91,50 @@ Accept pipeline input: True (ByValue) 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: 1 +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 +This cmdlet supports the common parameters: -Debug, -ErrorAction, +-ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, +-OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters +(). -### System.Object +## INPUTS +### [JiraPS.Filter] ## OUTPUTS -### System.Object +### [JiraPS.Filter] ## 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-JiraFilter](../Get-JiraFilter/) + +[Add-JiraFilterPermission](../Add-JiraFilterPermission/) + +[Remove-JiraFilterPermission](../Remove-JiraFilterPermission/) From 376e8919e0f22e6f1ae70133f63d0427592a14b3 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 14:02:02 +0200 Subject: [PATCH 63/83] Improved implementation of Add-JiraFilterPermission added proper tests --- JiraPS/Public/Add-JiraFilterPermission.ps1 | 32 +- Tests/Add-JiraFilterPermission.Tests.ps1 | 280 ++++++++++++++---- .../commands/Add-JiraFilterPermission.md | 51 +++- 3 files changed, 284 insertions(+), 79 deletions(-) diff --git a/JiraPS/Public/Add-JiraFilterPermission.ps1 b/JiraPS/Public/Add-JiraFilterPermission.ps1 index b0fa88c0..6e2ca439 100644 --- a/JiraPS/Public/Add-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Add-JiraFilterPermission.ps1 @@ -1,6 +1,6 @@ function Add-JiraFilterPermission { [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ByInputObject' )] - [OutputType( [JiraPS.FilterPermission] )] + # [OutputType( [JiraPS.FilterPermission] )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByInputObject' )] [ValidateNotNullOrEmpty()] @@ -8,14 +8,16 @@ $Filter, [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ById')] + [ValidateNotNullOrEmpty()] [UInt32[]] $Id, - [Parameter( Position = 1, Mandatory )] + [Parameter( Mandatory )] [ValidateNotNullOrEmpty()] [ValidateSet('Group', 'Project', 'ProjectRole', 'Authenticated', 'Global')] [String]$Type, + [Parameter()] [String]$Value, [Parameter()] @@ -35,9 +37,7 @@ Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" if ($PSCmdlet.ParameterSetName -eq 'ById') { - $InputObject = foreach ($_id in $Id) { - Get-JiraFilter -Id $_id - } + $Filter = Get-JiraFilter -Id $Id } $body = @{ @@ -57,17 +57,19 @@ "Global" { } } - $parameter = @{ - URI = $resourceURi -f $Filter.RestURL - Method = "POST" - Body = ConvertTo-Json $body - Credential = $Credential - } - Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - if ($PSCmdlet.ShouldProcess($Filter.Name, "Add Permission [$Type - $Value]")) { - $result = Invoke-JiraMethod @parameter + foreach ($_filter in $Filter) { + $parameter = @{ + URI = $resourceURi -f $_filter.RestURL + Method = "POST" + Body = ConvertTo-Json $body + Credential = $Credential + } + Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" + if ($PSCmdlet.ShouldProcess($_filter.Name, "Add Permission [$Type - $Value]")) { + $result = Invoke-JiraMethod @parameter - Write-Output (ConvertTo-JiraFilterPermission -InputObject $result) + Write-Output (ConvertTo-JiraFilter -InputObject $_filter -FilterPermissions $result) + } } } diff --git a/Tests/Add-JiraFilterPermission.Tests.ps1 b/Tests/Add-JiraFilterPermission.Tests.ps1 index 1d56300e..d1f947c5 100644 --- a/Tests/Add-JiraFilterPermission.Tests.ps1 +++ b/Tests/Add-JiraFilterPermission.Tests.ps1 @@ -11,14 +11,87 @@ Describe 'Add-JiraFilterPermission' { #region Definitions $jiraServer = "https://jira.example.com" - $responseFilter = @" -{ - "self": "$jiraServer/rest/api/latest/filter/12844", - "id": "12844", - "name": "{0}", - "jql": "{1}", - "favourite": false -} + $permissionJSON = @" +[ + { + "id": 10000, + "type": "global" + }, + { + "id": 10010, + "type": "project", + "project": { + "self": "$jiraServer/jira/rest/api/2/project/EX", + "id": "10000", + "key": "EX", + "name": "Example", + "avatarUrls": { + "48x48": "$jiraServer/jira/secure/projectavatar?size=large&pid=10000", + "24x24": "$jiraServer/jira/secure/projectavatar?size=small&pid=10000", + "16x16": "$jiraServer/jira/secure/projectavatar?size=xsmall&pid=10000", + "32x32": "$jiraServer/jira/secure/projectavatar?size=medium&pid=10000" + }, + "projectCategory": { + "self": "$jiraServer/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + }, + "simplified": false + } + }, + { + "id": 10010, + "type": "project", + "project": { + "self": "$jiraServer/jira/rest/api/2/project/MKY", + "id": "10002", + "key": "MKY", + "name": "Example", + "avatarUrls": { + "48x48": "$jiraServer/jira/secure/projectavatar?size=large&pid=10002", + "24x24": "$jiraServer/jira/secure/projectavatar?size=small&pid=10002", + "16x16": "$jiraServer/jira/secure/projectavatar?size=xsmall&pid=10002", + "32x32": "$jiraServer/jira/secure/projectavatar?size=medium&pid=10002" + }, + "projectCategory": { + "self": "$jiraServer/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + }, + "simplified": false + }, + "role": { + "self": "$jiraServer/jira/rest/api/2/project/MKY/role/10360", + "name": "Developers", + "id": 10360, + "description": "A project role that represents developers in a project", + "actors": [ + { + "id": 10240, + "displayName": "jira-developers", + "type": "atlassian-group-role-actor", + "name": "jira-developers" + }, + { + "id": 10241, + "displayName": "Fred F. User", + "type": "atlassian-user-role-actor", + "name": "fred" + } + ] + } + }, + { + "id": 10010, + "type": "group", + "group": { + "name": "jira-administrators", + "self": "$jiraServer/jira/rest/api/2/group?groupname=jira-administrators" + } + } +] "@ #endregion Definitions @@ -27,19 +100,32 @@ Describe 'Add-JiraFilterPermission' { $jiraServer } + Mock ConvertTo-JiraFilter -ModuleName JiraPS { + $i = New-Object -TypeName PSCustomObject + $i.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $i + } + Mock ConvertTo-JiraFilterPermission -ModuleName JiraPS { - $i = (ConvertFrom-Json $responseFilter) + $i = (ConvertFrom-Json $permissionJSON) $i.PSObject.TypeNames.Insert(0, 'JiraPS.FilterPermission') $i } Mock Get-JiraFilter -ModuleName JiraPS { - ConvertTo-JiraFilter + foreach ($_id in $Id) { + $object = New-Object -TypeName PSCustomObject -Property @{ + id = $_id + RestUrl = "$jiraServer/rest/api/latest/filter/$_id" + } + $object.PSObject.TypeNames.Insert(0, 'JiraPS.Filter') + $object + } } - Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Post' -and $URI -like "$jiraServer/rest/api/*/filter"} { + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Post' -and $URI -like "$jiraServer/rest/api/*/filter/*/permission"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'Body' - ConvertFrom-Json $responseFilter + ConvertFrom-Json $permissionJSON } Mock Invoke-JiraMethod -ModuleName JiraPS { @@ -52,73 +138,153 @@ Describe 'Add-JiraFilterPermission' { $command = Get-Command -Name Add-JiraFilterPermission defParam $command 'Filter' + defParam $command 'Id' defParam $command 'Type' defParam $command 'Value' defParam $command 'Credential' } Context "Behavior testing" { - It "Invokes the Jira API to create a filter" { + It "Adds share permission to Filter Object" { { - $newData = @{ - Name = "myName" - Description = "myDescription" - JQL = "myJQL" - Favorite = $true - } - New-JiraFilter @newData + Add-JiraFilterPermission -Filter (Get-JiraFilter -Id 12844) -Type "Global" } | Should Not Throw Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { $Method -eq 'Post' -and - $URI -like '*/rest/api/*/filter' -and - $Body -match "`"name`":\s*`"myName`"" -and - $Body -match "`"description`":\s*`"myDescription`"" -and - $Body -match "`"jql`":\s*`"myJQL`"" -and - $Body -match "`"favourite`":\s*true" + $URI -like '*/rest/api/*/filter/12844/permission' } + + Assert-MockCalled -CommandName ConvertTo-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It } - } - Context "Input testing" { - It "-Name and -JQL" { + It "Adds share permission to FilterId" { { - $parameter = @{ - Name = "newName" - JQL = "newJQL" - } - New-JiraFilter @parameter + Add-JiraFilterPermission -Id 12844 -Type "Global" } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter/12844/permission' + } + + Assert-MockCalled -CommandName ConvertTo-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It } - It "-Name and -Description and -JQL" { - { - $parameter = @{ - Name = "newName" - Description = "newDescription" - JQL = "newJQL" - } - New-JiraFilter @parameter - } | Should Not Throw + } - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + Context "Input testing" { + It "requires -Filter to be a JiraPS.Filter" { + { Add-JiraFilterPermission -Filter 1 -Type "Global" } | Should -Throw + { Add-JiraFilterPermission -Filter "lorem" -Type "Global" } | Should -Throw + { Add-JiraFilterPermission -Filter (Get-Date) -Type "Global" } | Should -Throw + + { Add-JiraFilterPermission -Filter (Get-JiraFilter -Id 1) -Type "Global" } | Should -Not -Throw } - It "-Name and -Description and -JQL and -Favorite" { - { - $parameter = @{ - Name = "newName" - Description = "newDescription" - JQL = "newJQL" - Favorite = $true - } - New-JiraFilter @parameter - } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It + It "allows a JiraPS.Filter to be passed over the pipeline" { + { Get-JiraFilter -Id 1 | Add-JiraFilterPermission -Type "Global" } | Should -Not -Throw + } + + It "can process multiple Filters" { + $filters = 1..5 | ForEach-Object { Get-JiraFilter -Id 1 } + $filters.Count | Should -Be 5 + + { Add-JiraFilterPermission -Filter $filters -Type "Global" } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 5 -Scope It } - It "maps the properties of an object to the parameters" { - { Get-JiraFilter "12345" | New-JiraFilter } | Should Not Throw + + It "can find a filter by it's Id" { + { Add-JiraFilterPermission -Id 1 -Type "Global" } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "allows for the filter's Id to be passed over the pipeline" { + { 1,2 | Add-JiraFilterPermission -Type "Global" } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 2 -Scope It + } + + It "can process mutiple FilterIds" { + { Add-JiraFilterPermission -Id 1,2,3,4,5 -Type "Global" } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-JiraFilter -ModuleName JiraPS -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 5 -Scope It + } + + It "accepts the 5 known permission types" { + { Add-JiraFilterPermission -Id 1 -Type "lorem" } | Should -Throw + { Add-JiraFilterPermission -Id 1 -Type "Invalid" } | Should -Throw + + { Add-JiraFilterPermission -Id 1 -Type "Global" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "Group" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "Project" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "ProjectRole" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "Authenticated" } | Should -Not -Throw + } + + It "does not validate -Value" { + { Add-JiraFilterPermission -Id 1 -Type "Global" -Value "invalid" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "Group" -Value "not a group" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "Project" -Value "not a project" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "ProjectRole" -Value "not a Role" } | Should -Not -Throw + { Add-JiraFilterPermission -Id 1 -Type "Authenticated" -Value "invalid" } | Should -Not -Throw + } + + It "constructs a valid request Body for type 'Global'" { + { Add-JiraFilterPermission -Id 12844 -Type "Global" } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter/12844/permission' -and + $Body -match '"type":\s*"global"' -and + $Body -notmatch ',' + } + } + + It "constructs a valid request Body for type 'Authenticated'" { + { Add-JiraFilterPermission -Id 12844 -Type "Authenticated" } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter/12844/permission' -and + $Body -match '"type":\s*"authenticated"' -and + $Body -notmatch "," + } + } + + It "constructs a valid request Body for type 'Group'" { + { Add-JiraFilterPermission -Id 12844 -Type "Group" -Value "administrators" } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter/12844/permission' -and + $Body -match '"type":\s*"group"' -and + $Body -match '"groupname":\s*"administrators"' + } + } + + It "constructs a valid request Body for type 'Project'" { + { Add-JiraFilterPermission -Id 12844 -Type "Project" -Value "11822" } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter/12844/permission' -and + $Body -match '"type":\s*"project"' -and + $Body -match '"projectId":\s*"11822"' + } + } + + It "constructs a valid request Body for type 'ProjectRole'" { + { Add-JiraFilterPermission -Id 12844 -Type "ProjectRole" -Value "11822" } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName JiraPS -Exactly -Times 1 -Scope It -ParameterFilter { + $Method -eq 'Post' -and + $URI -like '*/rest/api/*/filter/12844/permission' -and + $Body -match '"type":\s*"projectRole"' -and + $Body -match '"projectRoleId":\s*"11822"' + } } } } diff --git a/docs/en-US/commands/Add-JiraFilterPermission.md b/docs/en-US/commands/Add-JiraFilterPermission.md index ea354d97..ddfa6661 100644 --- a/docs/en-US/commands/Add-JiraFilterPermission.md +++ b/docs/en-US/commands/Add-JiraFilterPermission.md @@ -18,8 +18,9 @@ Share a Filter with other users. ### ByInputObject (Default) ```powershell -Add-JiraFilterPermission [-Filter] [-Type] [[-Value] ] - [[-Credential] ] [-WhatIf] [-Confirm] [] +Add-JiraFilterPermission [-Filter] [-Type] + [[-Value] ] [[-Credential] ] [-WhatIf] [-Confirm] + [] ``` ### ById @@ -71,8 +72,26 @@ Share Filter 12345 only with users in the administrators groups. Filter object to which the permission should be applied ```yaml -Type: Object -Parameter Sets: (All) +Type: JiraPS.Filter +Parameter Sets: ByInputObject +Aliases: + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +### -Id + +Id of the Filter to which the permission should be applied + +_Id can be passed over the pipeline when reading from a file._ + +```yaml +Type: UInt32[] +Parameter Sets: ById Aliases: Required: True @@ -178,8 +197,11 @@ 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). +This cmdlet supports the common parameters: -Debug, -ErrorAction, +-ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, +-OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters +(). ## INPUTS @@ -187,8 +209,23 @@ For more information, see about_CommonParameters (http://go.microsoft.com/fwlink ## OUTPUTS -### [JiraPS.FilterPermission] +### [JiraPS.Filter] ## NOTES +This functions does not validate the input for `-Value`. +In case the value is invalid, unexpected or missing, the API will response with +an error. + +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-JiraFilter](../Get-JiraFilter/) + +[Get-JiraFilterPermission](../Get-JiraFilterPermission/) + +[Remove-JiraFilterPermission](../Remove-JiraFilterPermission/) From bc73ac58bb0a9ad13423f0a751efd6e7d4df236e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 14:03:14 +0200 Subject: [PATCH 64/83] Implemented custom objects for FilterPermission --- JiraPS/Private/ConvertTo-JiraFilter.ps1 | 32 +++-- .../ConvertTo-JiraFilterPermission.ps1 | 2 +- JiraPS/Private/ConvertTo-JiraProjectRole.ps1 | 9 +- Tests/ConvertTo-JiraFilter.Tests.ps1 | 103 ++++++++++++++- .../ConvertTo-JiraFilterPermission.Tests.ps1 | 117 ++++++++++++++++++ Tests/ConvertTo-JiraProjectRole.Tests.ps1 | 49 ++++++++ 6 files changed, 293 insertions(+), 19 deletions(-) create mode 100644 Tests/ConvertTo-JiraFilterPermission.Tests.ps1 create mode 100644 Tests/ConvertTo-JiraProjectRole.Tests.ps1 diff --git a/JiraPS/Private/ConvertTo-JiraFilter.ps1 b/JiraPS/Private/ConvertTo-JiraFilter.ps1 index 6eb2be6f..15f1b635 100644 --- a/JiraPS/Private/ConvertTo-JiraFilter.ps1 +++ b/JiraPS/Private/ConvertTo-JiraFilter.ps1 @@ -3,7 +3,10 @@ function ConvertTo-JiraFilter { param( [Parameter( ValueFromPipeline )] [PSObject[]] - $InputObject + $InputObject, + + [PSObject[]] + $FilterPermissions ) process { @@ -11,17 +14,22 @@ function ConvertTo-JiraFilter { Write-Debug "[$($MyInvocation.MyCommand.Name)] Converting `$InputObject to custom object" $props = @{ - 'ID' = $i.id - 'Name' = $i.name - 'JQL' = $i.jql - 'RestUrl' = $i.self - 'ViewUrl' = $i.viewUrl - 'SearchUrl' = $i.searchUrl - 'Favourite' = $i.favourite - - 'SharePermission' = $i.sharePermissions - 'SharedUser' = $i.sharedUsers - 'Subscription' = $i.subscriptions + 'ID' = $i.id + 'Name' = $i.name + 'JQL' = $i.jql + 'RestUrl' = $i.self + 'ViewUrl' = $i.viewUrl + 'SearchUrl' = $i.searchUrl + 'Favourite' = $i.favourite + 'FilterPermissions' = @() + + 'SharePermission' = $i.sharePermissions + 'SharedUser' = $i.sharedUsers + 'Subscription' = $i.subscriptions + } + + if ($FilterPermissions) { + $props.FilterPermissions = @(ConvertTo-JiraFilterPermission ($FilterPermissions)) } if ($i.description) { diff --git a/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 b/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 index bdc9b0c6..95cd1225 100644 --- a/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 +++ b/JiraPS/Private/ConvertTo-JiraFilterPermission.ps1 @@ -30,7 +30,7 @@ function ConvertTo-JiraFilterPermission { $result = New-Object -TypeName PSObject -Property $props $result.PSObject.TypeNames.Insert(0, 'JiraPS.FilterPermission') $result | Add-Member -MemberType ScriptMethod -Name 'ToString' -Force -Value { - Write-Output "$($this.Id)" + Write-Output "$($this.Type)" } Write-Output $result diff --git a/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 b/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 index 685dfea9..aef189f7 100644 --- a/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 +++ b/JiraPS/Private/ConvertTo-JiraProjectRole.ps1 @@ -11,10 +11,11 @@ function ConvertTo-JiraProjectRole { Write-Debug "[$($MyInvocation.MyCommand.Name)] Converting `$InputObject to custom object" $props = @{ - 'ID' = $i.id - 'Name' = $i.name - 'RestUrl' = $i.self - 'ProjectId' = $i.projectId + 'ID' = $i.id + 'Name' = $i.name + 'Description' = $i.description + 'Actors' = $i.actors + 'RestUrl' = $i.self } $result = New-Object -TypeName PSObject -Property $props diff --git a/Tests/ConvertTo-JiraFilter.Tests.ps1 b/Tests/ConvertTo-JiraFilter.Tests.ps1 index c53fc172..0aa7e6a4 100644 --- a/Tests/ConvertTo-JiraFilter.Tests.ps1 +++ b/Tests/ConvertTo-JiraFilter.Tests.ps1 @@ -52,8 +52,97 @@ Describe "ConvertTo-JiraFilter" { } '@ + $samplePermission = @" +[ + { + "id": 10000, + "type": "global" + }, + { + "id": 10010, + "type": "project", + "project": { + "self": "$jiraServer/jira/rest/api/2/project/EX", + "id": "10000", + "key": "EX", + "name": "Example", + "avatarUrls": { + "48x48": "$jiraServer/jira/secure/projectavatar?size=large&pid=10000", + "24x24": "$jiraServer/jira/secure/projectavatar?size=small&pid=10000", + "16x16": "$jiraServer/jira/secure/projectavatar?size=xsmall&pid=10000", + "32x32": "$jiraServer/jira/secure/projectavatar?size=medium&pid=10000" + }, + "projectCategory": { + "self": "$jiraServer/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + }, + "simplified": false + } + }, + { + "id": 10010, + "type": "project", + "project": { + "self": "$jiraServer/jira/rest/api/2/project/MKY", + "id": "10002", + "key": "MKY", + "name": "Example", + "avatarUrls": { + "48x48": "$jiraServer/jira/secure/projectavatar?size=large&pid=10002", + "24x24": "$jiraServer/jira/secure/projectavatar?size=small&pid=10002", + "16x16": "$jiraServer/jira/secure/projectavatar?size=xsmall&pid=10002", + "32x32": "$jiraServer/jira/secure/projectavatar?size=medium&pid=10002" + }, + "projectCategory": { + "self": "$jiraServer/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + }, + "simplified": false + }, + "role": { + "self": "$jiraServer/jira/rest/api/2/project/MKY/role/10360", + "name": "Developers", + "id": 10360, + "description": "A project role that represents developers in a project", + "actors": [ + { + "id": 10240, + "displayName": "jira-developers", + "type": "atlassian-group-role-actor", + "name": "jira-developers" + }, + { + "id": 10241, + "displayName": "Fred F. User", + "type": "atlassian-user-role-actor", + "name": "fred" + } + ] + } + }, + { + "id": 10010, + "type": "group", + "group": { + "name": "jira-administrators", + "self": "$jiraServer/jira/rest/api/2/group?groupname=jira-administrators" + } + } +] +"@ + + Mock ConvertTo-JiraFilterPermission -ModuleName JiraPS { + $i = New-Object -TypeName PSCustomObject -Property @{ Id = 1111 } + $i.PSObject.TypeNames.Insert(0, 'JiraPS.FilterPermission') + $i + } + $sampleObject = ConvertFrom-Json -InputObject $sampleJson - $r = ConvertTo-JiraFilter -InputObject $sampleObject + $r = ConvertTo-JiraFilter -InputObject $sampleObject -FilterPermission $samplePermission It "Creates a PSObject out of JSON input" { $r | Should Not BeNullOrEmpty @@ -67,7 +156,17 @@ Describe "ConvertTo-JiraFilter" { defProp $r 'RestUrl' 'https://jira.atlassian.com/rest/api/latest/filter/12844' defProp $r 'ViewUrl' 'https://jira.atlassian.com/secure/IssueNavigator.jspa?mode=hide&requestId=12844' defProp $r 'SearchUrl' 'https://jira.atlassian.com/rest/api/latest/search?jql=project+%3D+10240+AND+issuetype+%3D+1+ORDER+BY+key+DESC' - defProp $r 'Favorite' $false + defProp $r 'Favourite' $false + It "Defines the 'Favorite' property as an alias of 'Favourite'" { + ($r | Get-Member -Name Favorite).MemberType | Should -Be "AliasProperty" + } + It "Uses output type of 'JiraPS.FilterPermission' for property 'FilterPermissions'" { + checkType $r.FilterPermissions 'JiraPS.FilterPermission' + } + + It "uses ConvertTo-JiraFilterPermission" { + Assert-MockCalled -CommandName ConvertTo-JiraFilterPermission -Module JiraPS -Exactly -Times 1 -Scope Describe + } } } diff --git a/Tests/ConvertTo-JiraFilterPermission.Tests.ps1 b/Tests/ConvertTo-JiraFilterPermission.Tests.ps1 new file mode 100644 index 00000000..2c4f1475 --- /dev/null +++ b/Tests/ConvertTo-JiraFilterPermission.Tests.ps1 @@ -0,0 +1,117 @@ +Describe "ConvertTo-JiraFilterPermission" { + + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + $sampleJson = @" +[ + { + "id": 10000, + "type": "global" + }, + { + "id": 10010, + "type": "project", + "project": { + "self": "$jiraServer/jira/rest/api/2/project/EX", + "id": "10000", + "key": "EX", + "name": "Example", + "avatarUrls": { + "48x48": "$jiraServer/jira/secure/projectavatar?size=large&pid=10000", + "24x24": "$jiraServer/jira/secure/projectavatar?size=small&pid=10000", + "16x16": "$jiraServer/jira/secure/projectavatar?size=xsmall&pid=10000", + "32x32": "$jiraServer/jira/secure/projectavatar?size=medium&pid=10000" + }, + "projectCategory": { + "self": "$jiraServer/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + }, + "simplified": false + } + }, + { + "id": 10010, + "type": "project", + "project": { + "self": "$jiraServer/jira/rest/api/2/project/MKY", + "id": "10002", + "key": "MKY", + "name": "Example", + "avatarUrls": { + "48x48": "$jiraServer/jira/secure/projectavatar?size=large&pid=10002", + "24x24": "$jiraServer/jira/secure/projectavatar?size=small&pid=10002", + "16x16": "$jiraServer/jira/secure/projectavatar?size=xsmall&pid=10002", + "32x32": "$jiraServer/jira/secure/projectavatar?size=medium&pid=10002" + }, + "projectCategory": { + "self": "$jiraServer/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + }, + "simplified": false + }, + "role": { + "self": "$jiraServer/jira/rest/api/2/project/MKY/role/10360", + "name": "Developers", + "id": 10360, + "description": "A project role that represents developers in a project", + "actors": [ + { + "id": 10240, + "displayName": "jira-developers", + "type": "atlassian-group-role-actor", + "name": "jira-developers" + }, + { + "id": 10241, + "displayName": "Fred F. User", + "type": "atlassian-user-role-actor", + "name": "fred" + } + ] + } + }, + { + "id": 10010, + "type": "group", + "group": { + "name": "jira-administrators", + "self": "$jiraServer/jira/rest/api/2/group?groupname=jira-administrators" + } + } +] +"@ + + $sampleObject = ConvertFrom-Json -InputObject $sampleJson + $r = ConvertTo-JiraFilterPermission -InputObject $sampleObject + + It "Creates a PSObject out of JSON input" { + $r | Should -Not -BeNullOrEmpty + } + + checkPsType $r 'JiraPS.FilterPermission' + + defProp $r 'Id' @(10000, 10010, 10010, 10010) + defProp $r 'Type' @('global', 'project', 'project', 'group') + It "Defines the 'Group' property of type 'JiraPS.Group'" { + checkType $r[3].Group 'JiraPS.Group' + $r.Group.Name | Should -Be 'jira-administrators' + } + It "Defines the 'Project' property of type 'JiraPS.Project'" { + checkType $r[1].Project 'JiraPS.Project' + $r.Project.Name | Should -Be @('Example', 'Example') + } + + It "Defines the 'Role' property of type 'JiraPS.ProjectRole'" { + checkType $r[2].Role 'JiraPS.ProjectRole' + $r.Role.Name | Should -Be 'Developers' + } + } +} diff --git a/Tests/ConvertTo-JiraProjectRole.Tests.ps1 b/Tests/ConvertTo-JiraProjectRole.Tests.ps1 new file mode 100644 index 00000000..acee0c95 --- /dev/null +++ b/Tests/ConvertTo-JiraProjectRole.Tests.ps1 @@ -0,0 +1,49 @@ +Describe "ConvertTo-JiraProjectRole" { + + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + + InModuleScope JiraPS { + + . "$PSScriptRoot/Shared.ps1" + + $sampleJson = @" +[ + { + "self": "http://www.example.com/jira/rest/api/2/project/MKY/role/10360", + "name": "Developers", + "id": 10360, + "description": "A project role that represents developers in a project", + "actors": [ + { + "id": 10240, + "displayName": "jira-developers", + "type": "atlassian-group-role-actor", + "name": "jira-developers" + }, + { + "id": 10241, + "displayName": "Fred F. User", + "type": "atlassian-user-role-actor", + "name": "fred" + } + ] + } +] +"@ + + $sampleObject = ConvertFrom-Json -InputObject $sampleJson + $r = ConvertTo-JiraProjectRole -InputObject $sampleObject + + It "Creates a PSObject out of JSON input" { + $r | Should -Not -BeNullOrEmpty + } + + checkPsType $r 'JiraPS.ProjectRole' + + defProp $r 'Id' 10360 + defProp $r 'Name' "Developers" + defProp $r 'Description' "A project role that represents developers in a project" + hasProp $r 'Actors' + defProp $r 'RestUrl' "http://www.example.com/jira/rest/api/2/project/MKY/role/10360" + } +} From e1884e9acd19ef704e2c829392933b9eae07ff73 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 14:03:57 +0200 Subject: [PATCH 65/83] Improved documentation of Filter functions --- JiraPS/Public/Remove-JiraFilter.ps1 | 1 + docs/en-US/commands/Get-JiraFilter.md | 28 +++++++++++++++++------- docs/en-US/commands/Remove-JiraFilter.md | 17 +++++++++----- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/JiraPS/Public/Remove-JiraFilter.ps1 b/JiraPS/Public/Remove-JiraFilter.ps1 index 8a892bdf..886a7709 100644 --- a/JiraPS/Public/Remove-JiraFilter.ps1 +++ b/JiraPS/Public/Remove-JiraFilter.ps1 @@ -7,6 +7,7 @@ function Remove-JiraFilter { $InputObject, [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ById')] + [ValidateNotNullOrEmpty()] [UInt32[]] $Id, diff --git a/docs/en-US/commands/Get-JiraFilter.md b/docs/en-US/commands/Get-JiraFilter.md index 7ff88bf8..47d95c19 100644 --- a/docs/en-US/commands/Get-JiraFilter.md +++ b/docs/en-US/commands/Get-JiraFilter.md @@ -24,7 +24,8 @@ Get-JiraFilter [-Id] [-Credential ] [ ### ByInputObject ```powershell -Get-JiraFilter -InputObject [-Credential ] [] +Get-JiraFilter -InputObject [-Credential ] + [] ``` ### MyFavorite @@ -35,13 +36,14 @@ Get-JiraFilter -Favorite [-Credential ] [] ## DESCRIPTION -This function returns information about a filter in JIRA, including the JQL syntax of the filter, its owner, and sharing status. +This function returns information about a filter in JIRA, including the JQL +syntax of the filter, its owner, and sharing status. This function is only capable of returning filters by their Filter ID. This is a limitation of JIRA's REST API. -The easiest way to obtain the ID of a filter is to load the filter in the "regular" Web view of JIRA, -then copy the ID from the URL of the page. +The easiest way to obtain the ID of a filter is to load the filter in the +"regular" Web view of JIRA, then copy the ID from the URL of the page. ## EXAMPLES @@ -139,12 +141,15 @@ 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). +This cmdlet supports the common parameters: -Debug, -ErrorAction, +-ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, +-OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters +(). ## INPUTS -### [JiraPS.Filter[]] / [String[]] +### [JiraPS.Filter] / [String] The filter to look up in JIRA. This can be a String (filter ID) or a JiraPS.Filter object. @@ -154,7 +159,8 @@ The filter to look up in JIRA. This can be a String (filter ID) or a JiraPS.Filt ## NOTES -This function requires either the `-Credential` parameter to be passed or a persistent JIRA session. +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. @@ -165,3 +171,9 @@ If neither are supplied, this function will run with anonymous access to JIRA. [Set-JiraFilter](../Set-JiraFilter/) [Remove-JiraFilter](../Remove-JiraFilter/) + +[Add-JiraFilterPermission](../Add-JiraFilterPermission/) + +[Get-JiraFilterPermission](../Get-JiraFilterPermission/) + +[Remove-JiraFilterPermission](../Remove-JiraFilterPermission/) diff --git a/docs/en-US/commands/Remove-JiraFilter.md b/docs/en-US/commands/Remove-JiraFilter.md index b5fbc5a2..66dd3b5c 100644 --- a/docs/en-US/commands/Remove-JiraFilter.md +++ b/docs/en-US/commands/Remove-JiraFilter.md @@ -18,7 +18,8 @@ Removes an existing filter. ### byInputObject (Default) ```powershell -Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] [] +Remove-JiraFilter [-InputObject] [-WhatIf] [-Confirm] + [] ``` ### byId (Default) @@ -76,8 +77,8 @@ $listOfFilters | Remove-JiraFilter Remove filters with id "1", "2", "3" and "4". -This input allows for the ID of the filters to be stored in an array and passed to -the command. (eg: `Get-Content` from a file with the ids) +This input allows for the ID of the filters to be stored in an array and passed +to the command. (eg: `Get-Content` from a file with the ids) ## PARAMETERS @@ -169,8 +170,11 @@ 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). +This cmdlet supports the common parameters: -Debug, -ErrorAction, +-ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, +-OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. +For more information, see about_CommonParameters +(). ## INPUTS @@ -180,7 +184,8 @@ For more information, see about_CommonParameters (http://go.microsoft.com/fwlink ## NOTES -This function requires either the `-Credential` parameter to be passed or a persistent JIRA session. +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. From 7a5c2fdcf9674271267a12bd779cd0b458edbe6a Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 14:04:28 +0200 Subject: [PATCH 66/83] Updated Tests for the Help-engine --- Tests/JiraPS.Help.Tests.ps1 | 397 ++++++++++++++++++++---------------- 1 file changed, 226 insertions(+), 171 deletions(-) diff --git a/Tests/JiraPS.Help.Tests.ps1 b/Tests/JiraPS.Help.Tests.ps1 index 46bf7d6d..08cc814e 100644 --- a/Tests/JiraPS.Help.Tests.ps1 +++ b/Tests/JiraPS.Help.Tests.ps1 @@ -1,205 +1,260 @@ -<# - .NOTES - =========================================================================== - Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.119 - Created on: 4/12/2016 1:11 PM - Created by: June Blender - Organization: SAPIEN Technologies, Inc - Filename: *.Help.Tests.ps1 - =========================================================================== - .DESCRIPTION - To test help for the commands in a module, place this file in the module folder. - To test any module from any path, use https://github.com/juneb/PesterTDD/Module.Help.Tests.ps1 -#> - -<# -.SYNOPSIS -Gets command parameters; one per name. Prefers default parameter set. - -.DESCRIPTION -Gets one CommandParameterInfo object for each parameter in the specified -command. If a command has more than one parameter with the same name, this -function gets the parameters in the default parameter set, if one is specified. - -For example, if a command has two parameter sets: - Name, ID (default) - Name, Path -This function returns: - Name (default), ID Path - -This function is used to get parameters for help and for help testing. - -.PARAMETER Command -Enter a CommandInfo object, such as the object that Get-Command returns. You -can also pipe a CommandInfo object to the function. - -This parameter takes a CommandInfo object, instead of a command name, so -you can use the parameters of Get-Command to specify the module and version -of the command. - -.EXAMPLE -PS C:\> Get-ParametersDefaultFirst -Command (Get-Command New-Guid) -This command uses the Command parameter to specify the command to -Get-ParametersDefaultFirst - -.EXAMPLE -PS C:\> Get-Command New-Guid | Get-ParametersDefaultFirst -You can also pipe a CommandInfo object to Get-ParametersDefaultFirst - -.EXAMPLE -PS C:\> Get-ParametersDefaultFirst -Command (Get-Command BetterCredentials\Get-Credential) -You can use the Command parameter to specify the CommandInfo object. This -command runs Get-Command module-qualified name value. - -.EXAMPLE -PS C:\> $ModuleSpec = @{ModuleName='BetterCredentials';RequiredVersion=4.3} -PS C:\> Get-Command -FullyQualifiedName $ModuleSpec | Get-ParametersDefaultFirst -This command uses a Microsoft.PowerShell.Commands.ModuleSpecification object to -specify the module and version. You can also use it to specify the module GUID. -Then, it pipes the CommandInfo object to Get-ParametersDefaultFirst. -#> -function Get-ParametersDefaultFirst { - param - ( - [Parameter(Mandatory = $true, - ValueFromPipeline = $true)] - [System.Management.Automation.CommandInfo] - $Command - ) +#requires -modules BuildHelpers +#requires -modules Pester - BEGIN { - $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' - $parameters = @() - } - PROCESS { - if ($defaultPSetName = $Command.DefaultParameterSet) { - $defaultParameters = ($Command.ParameterSets | Where-Object Name -eq $defaultPSetName).parameters | Where-Object Name -NotIn $common - $otherParameters = ($Command.ParameterSets | Where-Object Name -ne $defaultPSetName).parameters | Where-Object Name -NotIn $common - - $parameters += $defaultParameters - if ($parameters -and $otherParameters) { - $otherParameters | ForEach-Object { - if ($_.Name -notin $parameters.Name) { - $parameters += $_ - } - } - $parameters = $parameters | Sort-Object Name - } +Describe "Help tests" -Tag Documentation { + + BeforeAll { + Import-Module BuildHelpers + Remove-Item -Path Env:\BH* + + $projectRoot = (Resolve-Path "$PSScriptRoot/..").Path + if ($projectRoot -like "*Release") { + $projectRoot = (Resolve-Path "$projectRoot/..").Path } - else { - $parameters = $Command.ParameterSets.Parameters | Where-Object Name -NotIn $common | Sort-Object Name -Unique + Set-BuildEnvironment -BuildOutput '$ProjectPath/Release' -Path $projectRoot -ErrorAction SilentlyContinue + $env:BHManifestToTest = $env:BHPSModuleManifest + $isBuild = $PSScriptRoot -like "$env:BHBuildOutput*" + if ($isBuild) { + $Pattern = [regex]::Escape($env:BHProjectPath) + + $env:BHBuildModuleManifest = $env:BHPSModuleManifest -replace $Pattern, $env:BHBuildOutput + $env:BHManifestToTest = $env:BHBuildModuleManifest } - return $parameters + 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* } - END { } -} -$ModuleBase = "$PSScriptRoot\..\JiraPS" + $DefaultParams = @( + 'Verbose' + 'Debug' + 'ErrorAction' + 'WarningAction' + 'InformationAction' + 'ErrorVariable' + 'WarningVariable' + 'InformationVariable' + 'OutVariable' + 'OutBuffer' + 'PipelineVariable' + 'WhatIf' + 'Confirm' + ) -# Handles modules in version directories -$leaf = Split-Path $ModuleBase -Leaf -$parent = Split-Path $ModuleBase -Parent -$parsedVersion = $null -if ([System.Version]::TryParse($leaf, [ref]$parsedVersion)) { - $ModuleName = Split-Path $parent -Leaf -} -else { - $ModuleName = $leaf -} + $module = Get-Module $env:BHProjectName + $commands = Get-Command -Module $module -CommandType Cmdlet, Function, Workflow # Not alias + $classes = Get-ChildItem "$env:BHProjectPath/docs/en-US/classes/*" -ErrorAction SilentlyContinue + $enums = Get-ChildItem "$env:BHProjectPath/docs/en-US/enumerations/*" -ErrorAction SilentlyContinue -# Removes all versions of the module from the session before importing -Get-Module $moduleName | Remove-Module + #region Public Functions + foreach ($command in $commands) { + $commandName = $command.Name -replace $module.Prefix, '' + $markdownFile = Resolve-Path "$env:BHProjectPath/docs/en-US/commands/$commandName.md" -$Module = Import-Module $ModuleBase\$ModuleName.psd1 -PassThru -ErrorAction Stop -$commands = Get-Command -Module $module -CommandType Cmdlet, Function, Workflow # Not alias + # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets + $help = Get-Help $command.Name -ErrorAction Stop -## When testing help, remember that help is cached at the beginning of each session. -## To test, restart session. + Context "Function $commandName's Help" { -foreach ($command in $commands) { - $commandName = $command.Name + #region PlatyPS external Help + It "is described in a markdown file" { + $markdownFile | Should -Not -BeNullOrEmpty + Test-Path $markdownFile | Should -Be $true + } - # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets - $Help = Get-Help $commandName -ErrorAction Stop + It "does not have Comment-Based Help" { + # We use .EXAMPLE, as we test this extensivly and it is never auto-generated + $command.Definition | Should -Not -BeNullOrEmpty + $Pattern = [regex]::Escape(".EXAMPLE") - Describe "Test help for $commandName" -Tag "CommandHelp" { + $command.Definition | Should -Not -Match "^\s*$Pattern" + } - # If help is not found, synopsis in auto-generated help is the syntax diagram - It "should not be auto-generated" { - $Help.Synopsis | Should Not BeLike '*`[``]*' - } + It "has no platyPS template artifacts" { + $markdownFile | Should -Not -BeNullOrEmpty + $markdownFile | Should -Not -FileContentMatch '{{.*}}' + } - # Should be a synopsis for every function - It "gets synopsis for $commandName" { - $Help.Synopsis | Should Not beNullOrEmpty - } + It "has a link to the 'Online Version'" { + [Uri]$onlineLink = ($help.relatedLinks.navigationLink | Where-Object linkText -eq "Online Version:").Uri - # Should be a description for every function - It "gets description for $commandName" { - $Help.Description | Should Not BeNullOrEmpty - } + $onlineLink.Authority | Should -Be "atlassianps.org" + $onlineLink.Scheme | Should -Be "https" + $onlineLink.PathAndQuery | Should -Be "/docs/$env:BHProjectName/commands/$commandName/" + } - # Should be at least one example - It "gets example code from $commandName" { - ($Help.Examples.Example | Select-Object -First 1).Code | Should Not BeNullOrEmpty - } + it "has a valid HelpUri" { + $command.HelpUri | Should -Not -BeNullOrEmpty + $Pattern = [regex]::Escape("https://atlassianps.org/docs/$env:BHProjectName/commands/$commandName") - # Should be at least one example description - It "gets example help from $commandName" { - ($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should Not BeNullOrEmpty - } + $command.HelpUri | Should -Match $Pattern + } - It "has at least as many examples as ParameterSets" { - ($Help.Examples.Example | Measure-Object).Count | Should Not BeLessThan $command.ParameterSets.Count - } + It "defines the frontmatter for the homepage" { + $markdownFile | Should -Not -BeNullOrEmpty + $markdownFile | Should -FileContentMatch "Module Name: $env:BHProjectName" + $markdownFile | Should -FileContentMatchExactly "layout: documentation" + $markdownFile | Should -FileContentMatch "permalink: /docs/$env:BHProjectName/commands/$commandName/" + } + #endregion PlatyPS external Help + + #region Help Content + It "has a synopsis" { + $help.Synopsis | Should -Not -BeNullOrEmpty + } + + It "has a description" { + $help.Description.Text -join '' | Should -Not -BeNullOrEmpty + } + + It "has examples" { + ($help.Examples.Example | Select-Object -First 1).Code | Should -Not -BeNullOrEmpty + } + + It "has desciptions for all examples" { + foreach ($example in ($help.Examples.Example)) { + $example.remarks.Text | Should -Not -BeNullOrEmpty + } + } + + It "has at least as many examples as ParameterSets" { + ($help.Examples.Example | Measure-Object).Count | Should -BeGreaterOrEqual $command.ParameterSets.Count + } + #endregion Help Content + + #region Consistency with Code + # It "does not define parameter position for functions with only one ParameterSet" { + # if ($command.ParameterSets.Count -eq 1) { + # $command.Parameters.Keys | Foreach-Object { + # $command.Parameters[$_].ParameterSets.Values.Position | Should -BeLessThan 0 + # } + # } + # } + + It "has all ParameterSets in the Help" { + # @($command.ParameterSets).Count | Should -Be @($help.Syntax.SyntaxItem).Count + } - Context "Test parameter help for $commandName" { - # Get parameters. When >1 parameter with same name, - # get parameter from the default parameter set, if any. - if ($parameters = Get-ParametersDefaultFirst -Command $command) { - $parameterNames = $parameters.Name - $HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique - - foreach ($parameter in $parameters) { - $parameterName = $parameter.Name - $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName - - # Should be a description for every parameter - if ($parameterName -notmatch 'Confirm|WhatIf') { - It "gets help for parameter: $parameterName : in $commandName" { - $parameterHelp.Description.Text | Should Not BeNullOrEmpty + #region Parameters + foreach ($parameterName in $command.Parameters.Keys) { + $parameterCode = $command.Parameters[$parameterName] + + if ($help.Parameters | Get-Member -Name Parameter) { + $parameterHelp = $help.Parameters.Parameter | Where-Object Name -EQ $parameterName + + if ($parameterName -notin $DefaultParams) { + It "has a description for parameter [-$parameterName] in $commandName" { + $parameterHelp.Description.Text | Should -Not -BeNullOrEmpty } - } - # Required value in Help should match IsMandatory property of parameter - It "help for $parameterName parameter in $commandName has correct Mandatory value" { - $codeMandatory = $parameter.IsMandatory.toString() - $parameterHelp.Required | Should Be $codeMandatory - } + It "has a mandatory flag for parameter [-$parameterName] in $commandName" { + $isMandatory = $parameterCode.ParameterSets.Values.IsMandatory -contains "True" - # Parameter type in Help should match code - It "help for $commandName has correct parameter type for $parameterName" { - $codeType = $parameter.ParameterType.Name - if ($codeType -eq "Object") { - if (($parameter.Attributes) -and ($parameter.Attributes | Get-Member -Name PSTypeName)) { - $codeType = $parameter.Attributes[0].PSTypeName + $parameterHelp.Required | Should -BeLike $isMandatory.ToString() + } + + It "matches the type of the parameter [-$parameterName] in code and help of $commandName" { + $codeType = $parameterCode.ParameterType.Name + if ($codeType -eq "Object") { + if (($parameterCode.Attributes) -and ($parameterCode.Attributes | Get-Member -Name PSTypeName)) { + $codeType = $parameterCode.Attributes[0].PSTypeName + } } + # To avoid calling Trim method on a null object. + $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } + if ($helpType -eq "PSCustomObject") { $helpType = "PSObject" } + + $helpType | Should -Be $codeType } - # To avoid calling Trim method on a null object. - $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } - if ($helpType -eq "PSCustomObject") { $helpType = "PSObject" } - $helpType | Should be $codeType } } - foreach ($helpParm in $HelpParameterNames) { - # Shouldn't find extra parameters in help. - It "finds help parameter in code: $helpParm" { - $helpParm -in $parameterNames | Should Be $true + It "does not have parameters that are not in the code" { + $parameter = @() + if ($help.Parameters | Get-Member -Name Parameter) { + $parameter = $help.Parameters.Parameter.Name | Sort-Object -Unique } + foreach ($helpParm in $parameter) { + $command.Parameters.Keys | Should -Contain $helpParm + } + } + } + #endregion Parameters + #endregion Consistency with Code + } + } + #endregion Public Functions + + #region Classes + if ($classes) { + foreach ($class in $classes) { + Context "Classes $($class.BaseName) Help" { + + It "is described in a markdown file" { + $class.FullName | Should -Not -BeNullOrEmpty + Test-Path $class.FullName | Should -Be $true + } + + It "has no platyPS template artifacts" { + $class.FullName | Should -Not -BeNullOrEmpty + $class.FullName | Should -Not -FileContentMatch '{{.*}}' + } + + It "defines the frontmatter for the homepage" { + $class.FullName | Should -Not -BeNullOrEmpty + $class.FullName | Should -FileContentMatch "Module Name: $env:BHProjectName" + $class.FullName | Should -FileContentMatchExactly "layout: documentation" + $class.FullName | Should -FileContentMatch "permalink: /docs/$env:BHProjectName/classes/$commandName/" + } + } + } + + Context "Missing classes" { + It "has a documentation file for every class" { + foreach ($class in ([AtlassianPS.ServerData].Assembly.GetTypes() | Where-Object IsClass)) { + $classes.BaseName | Should -Contain $class.FullName + } + } + } + } + #endregion Classes + + #region Enumerations + if ($enums) { + foreach ($enum in $enums) { + Context "Enumeration $($enum.BaseName) Help" { + + It "is described in a markdown file" { + $enum.FullName | Should -Not -BeNullOrEmpty + Test-Path $enum.FullName | Should -Be $true + } + + It "has no platyPS template artifacts" { + $enum.FullName | Should -Not -BeNullOrEmpty + $enum.FullName | Should -Not -FileContentMatch '{{.*}}' + } + + It "defines the frontmatter for the homepage" { + $enum.FullName | Should -Not -BeNullOrEmpty + $enum.FullName | Should -FileContentMatch "Module Name: $env:BHProjectName" + $enum.FullName | Should -FileContentMatchExactly "layout: documentation" + $enum.FullName | Should -FileContentMatch "permalink: /docs/$env:BHProjectName/enumerations/$commandName/" + } + } + } + + Context "Missing classes" { + It "has a documentation file for every class" { + foreach ($enum in ([AtlassianPS.ServerData].Assembly.GetTypes() | Where-Object IsEnum)) { + $enums.BaseName | Should -Contain $enum.FullName } } } } + #endregion Enumerations } From 6f25903e5e9bb42aef5819292317336785e2b660 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Thu, 21 Jun 2018 14:16:19 +0200 Subject: [PATCH 67/83] Upgraded Pester to 4.3.1 --- Tools/build.requirements.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/build.requirements.psd1 b/Tools/build.requirements.psd1 index 7c0668f0..48501742 100644 --- a/Tools/build.requirements.psd1 +++ b/Tools/build.requirements.psd1 @@ -14,7 +14,7 @@ Parameters = @{ SkipPublisherCheck = $true } - Version = "4.1.1" + Version = "4.3.1" } platyPS = "latest" PSScriptAnalyzer = @{ From c6cc29a676830b96a65be5de5817f628895f0812 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 19:27:16 +0200 Subject: [PATCH 68/83] Fixed tests after changes to Invoke-JiraMethod --- Tests/Get-JiraVersion.Tests.ps1 | 179 +++++++++++++++-------------- Tests/New-JiraSession.Tests.ps1 | 98 ++++++++++------ Tests/Remove-JiraSession.Tests.ps1 | 80 +++---------- 3 files changed, 173 insertions(+), 184 deletions(-) diff --git a/Tests/Get-JiraVersion.Tests.ps1 b/Tests/Get-JiraVersion.Tests.ps1 index ea38511d..2af2a5e1 100644 --- a/Tests/Get-JiraVersion.Tests.ps1 +++ b/Tests/Get-JiraVersion.Tests.ps1 @@ -1,15 +1,19 @@ Describe "Get-JiraVersion" { - Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } InModuleScope JiraPS { . "$PSScriptRoot/Shared.ps1" + #region Definitions $jiraServer = 'http://jiraserver.example.com' - $versionName1 = '1.0.0.0' - $versionName2 = '2.0.0.0' - $versionName3 = '3.0.0.0' + $versionName1 = 'v1.0' + $versionName2 = 'v2.0' + $versionName3 = 'v3.0' $versionID1 = 16740 $versionID2 = 16840 $versionID3 = 16940 @@ -79,8 +83,9 @@ Describe "Get-JiraVersion" { "released" : "False", "projectId" : "$projectId" } -} +] "@ + #endregion Definitions #region Mocks Mock Get-JiraConfigServer -ModuleName JiraPS { @@ -121,7 +126,7 @@ Describe "Get-JiraVersion" { Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter { $Method -eq 'Get' -and $URI -like "$jiraServer/rest/api/*/project/*/version" } { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - ConvertFrom-Json $testJson1 + ConvertFrom-Json $testJsonAll } # Generic catch-all. This will throw an exception if we forgot to mock something. @@ -145,7 +150,7 @@ Describe "Get-JiraVersion" { It "gets a Version using Id Parameter Set" { $results = Get-JiraVersion -Id $versionID1 - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -161,11 +166,11 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 1 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 } Assert-MockCalled @assertMockCalledSplat } @@ -173,7 +178,7 @@ Describe "Get-JiraVersion" { It "gets a Version using multiple IDs" { $results = Get-JiraVersion -Id $versionID1, $versionID2 - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -202,11 +207,11 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 2 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 2 } Assert-MockCalled @assertMockCalledSplat } @@ -216,9 +221,9 @@ Describe "Get-JiraVersion" { $version2 = ConvertTo-JiraVersion ([PSCustomObject]@{Id = [int]($versionID2); project = "lorem"}) $results1 = ($version1 | Get-JiraVersion) - $results2 = ($version1 | Get-JiraVersion) - $results1 | Should Not BeNullOrEmpty - $results2 | Should Not BeNullOrEmpty + $results2 = ($version2 | Get-JiraVersion) + $results1 | Should -Not -BeNullOrEmpty + $results2 | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -234,11 +239,11 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 4 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 4 } Assert-MockCalled @assertMockCalledSplat } @@ -246,7 +251,7 @@ Describe "Get-JiraVersion" { It "gets all Versions using Project Parameter Set" { $results = Get-JiraVersion -Project $projectKey - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -263,20 +268,20 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'Get-JiraProject' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 1 + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 } Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 0 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 } Assert-MockCalled @assertMockCalledSplat } @@ -284,14 +289,14 @@ Describe "Get-JiraVersion" { It "gets all Versions using Project as pipe input" { $results = Get-JiraProject -Project $projectKey | Get-JiraVersion - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' ModuleName = 'JiraPS' ParameterFilter = { $Method -eq 'Get' -and - $URI -like "*/rest/api/*/project/$projectKey/version"-and + $URI -like "*/rest/api/*/project/$projectKey/version" -and $Paging -eq $true } Scope = 'It' @@ -303,20 +308,20 @@ Describe "Get-JiraVersion" { # Get-JiraProject is called once in the It block # and once in the `Get-JiraVersion` $assertMockCalledSplat = @{ - CommandName = 'Get-JiraProject' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 2 + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 2 } Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 0 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 } Assert-MockCalled @assertMockCalledSplat } @@ -324,14 +329,14 @@ Describe "Get-JiraVersion" { It "gets all Versions from multiple Projects" { $results = Get-JiraVersion -Project $projectKey, "foo" - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' ModuleName = 'JiraPS' ParameterFilter = { $Method -eq 'Get' -and - $URI -like "*/rest/api/*/project/*/version"-and + $URI -like "*/rest/api/*/project/*/version" -and $Paging -eq $true } Scope = 'It' @@ -341,20 +346,20 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'Get-JiraProject' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 2 + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 2 } Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 0 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 } Assert-MockCalled @assertMockCalledSplat } @@ -362,14 +367,14 @@ Describe "Get-JiraVersion" { It "filters the Versions from a Project by Name" { $results = Get-JiraVersion -Project $projectKey -Name $versionName1 - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' ModuleName = 'JiraPS' ParameterFilter = { $Method -eq 'Get' -and - $URI -like "*/rest/api/*/project/*/version"-and + $URI -like "*/rest/api/*/project/*/version" -and $Paging -eq $true } Scope = 'It' @@ -379,20 +384,20 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'Get-JiraProject' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 1 + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 } Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 0 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 } Assert-MockCalled @assertMockCalledSplat } @@ -400,14 +405,14 @@ Describe "Get-JiraVersion" { It "filters the Versions from a Project by multiple Names" { $results = Get-JiraVersion -Project $projectKey -Name $versionName1, $versionName2 - $results | Should Not BeNullOrEmpty + $results | Should -Not -BeNullOrEmpty $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' ModuleName = 'JiraPS' ParameterFilter = { $Method -eq 'Get' -and - $URI -like "*/rest/api/*/project/*/version"-and + $URI -like "*/rest/api/*/project/*/version" -and $Paging -eq $true } Scope = 'It' @@ -417,26 +422,26 @@ Describe "Get-JiraVersion" { Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'Get-JiraProject' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 1 + CommandName = 'Get-JiraProject' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 1 } Assert-MockCalled @assertMockCalledSplat $assertMockCalledSplat = @{ - CommandName = 'ConvertTo-JiraVersion' - ModuleName = 'JiraPS' - Scope = 'It' - Exactly = $true - Times = 0 + CommandName = 'ConvertTo-JiraVersion' + ModuleName = 'JiraPS' + Scope = 'It' + Exactly = $true + Times = 0 } Assert-MockCalled @assertMockCalledSplat } It "Supports the -Skip parameters to page through search results" { - { Get-JiraVersion -Project $projectKey -Skip 10 } | Should Not Throw + { Get-JiraVersion -Project $projectKey -Skip 10 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' @@ -455,7 +460,7 @@ Describe "Get-JiraVersion" { } It "Supports the -First parameters to page through search results" { - { Get-JiraVersion -Project $projectKey -First 50 } | Should Not Throw + { Get-JiraVersion -Project $projectKey -First 50 } | Should -Not -Throw $assertMockCalledSplat = @{ CommandName = 'Invoke-JiraMethod' diff --git a/Tests/New-JiraSession.Tests.ps1 b/Tests/New-JiraSession.Tests.ps1 index 1526d4ce..ef6f9f4d 100644 --- a/Tests/New-JiraSession.Tests.ps1 +++ b/Tests/New-JiraSession.Tests.ps1 @@ -1,66 +1,92 @@ -[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] -param() - Describe "New-JiraSession" { - -Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + AfterEach { + try { + (Get-Module JiraPS).PrivateData.Remove("Session") + } + catch { $null = 0 } + } InModuleScope JiraPS { . "$PSScriptRoot/Shared.ps1" + #region Definitions $jiraServer = 'http://jiraserver.example.com' - $authUri = "$jiraServer/rest/api/*/mypermissions" - - $testUsername = 'powershell-test' - $testPassword = ConvertTo-SecureString -String 'test123' -AsPlainText -Force - $testCredential = New-Object -TypeName PSCredential -ArgumentList $testUsername, $testPassword - $testJson = "{}" - $global:newSessionVar = @{} + $testCredential = [System.Management.Automation.PSCredential]::Empty + #endregion Definitions + #region Mocks Mock Get-JiraConfigServer -ModuleName JiraPS { Write-Output $jiraServer } - Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Method -eq 'Get' -and $Uri -like $authUri} { + Mock ConvertTo-JiraSession -ModuleName JiraPS { } + + Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $Uri -like "*/rest/api/*/mypermissions"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - Write-Output $testJson + [Microsoft.PowerShell.Commands.WebRequestSession]::new() } - Mock Invoke-WebRequest { + Mock Invoke-JiraMethod -ModuleName JiraPS { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' throw "Unidentified call to Invoke-JiraMethod" } + #endregion Mocks - It "Invokes a REST method directly to the JIRA server" { - New-JiraSession -Credential $testCredential - Assert-MockCalled -CommandName Invoke-WebRequest -Exactly -Times 1 -Scope It - } + Context "Sanity checking" { + $command = Get-Command -Name New-JiraSession - It "Uses the -UseBasicParsing switch for Invoke-WebRequest" { - { New-JiraSession -Credential $testCredential } | Should Not Throw - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$UseBasicParsing -eq $true} -Scope It + defParam $command 'Credential' + defParam $command 'Headers' } - It "Provides the JSessionID of the session in Jira" { - $s = New-JiraSession -Credential $testCredential - $s.JSessionID | Should Be $jSessionId - } + Context "Behavior testing" { + It "uses Basic Authentication to generate a session" { + { New-JiraSession -Credential $testCredential } | Should -Not -Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Credential -eq $testCredential + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } - It "Stores the session variable in the module's PrivateData" { - $s = New-JiraSession -Credential $testCredential - $s2 = Get-JiraSession - $s2 | Should Be $s - } + It "can influence the Headers used in the request" { + { New-JiraSession -Credential $testCredential -Headers @{ "X-Header" = $true } } | Should -Not -Throw + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-JiraMethod' + ModuleName = 'JiraPS' + ParameterFilter = { + $Headers.ContainsKey("X-Header") + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + + It "stores the session variable in the module's PrivateData" { + (Get-Module JiraPS).PrivateData.Session | Should -BeNullOrEmpty - Context "Output checking" { - Mock ConvertTo-JiraSession {} - New-JiraSession -Credential $testCredential + New-JiraSession -Credential $testCredential - It "Uses ConvertTo-JiraSession to beautify output" { - Assert-MockCalled 'ConvertTo-JiraSession' + (Get-Module JiraPS).PrivateData.Session | Should -Not -BeNullOrEmpty } } + + Context "Input testing" { } } } diff --git a/Tests/Remove-JiraSession.Tests.ps1 b/Tests/Remove-JiraSession.Tests.ps1 index b758e5bc..a194ecb9 100644 --- a/Tests/Remove-JiraSession.Tests.ps1 +++ b/Tests/Remove-JiraSession.Tests.ps1 @@ -1,73 +1,31 @@ -[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] -param() - Describe "Remove-JiraSession" { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } - Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop - - InModuleScope JiraPS { - - . "$PSScriptRoot/Shared.ps1" - - $jiraServer = 'http://jiraserver.example.com' - $authUri = "$jiraServer/rest/api/*/mypermissions" - $jSessionId = '76449957D8C863BE8D4F6F5507E980E8' - - $testUsername = 'powershell-test' - $testPassword = ConvertTo-SecureString -String 'test123' -AsPlainText -Force - $testCredential = New-Object -TypeName PSCredential -ArgumentList $testUsername, $testPassword - - $testJson = @" -{ -} -"@ + . "$PSScriptRoot/Shared.ps1" - Mock Get-JiraConfigServer -ModuleName JiraPS { - Write-Output $jiraServer - } - - Mock Invoke-WebRequest -Verifiable -ParameterFilter {$Method -eq 'GET' -and $Uri -like $authUri} { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - $global:newSessionVar = @{} - Write-Output $testJson - } - - Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - throw "Unidentified call to Invoke-JiraMethod" - } + #region Mocks + Mock Get-JiraSession -ModuleName JiraPS { + (Get-Module JiraPS).PrivateData.Session + } + #endregion Mocks - It "Closes a saved JiraPS.Session object from module PrivateData" { + Context "Sanity checking" { + $command = Get-Command -Name Remove-JiraSession - # This probably isn't the best test for this, but it's about all I can come up with at the moment. - # New-JiraSession has some slightly more elaborate testing, which includes a test for Get-JiraSession, - # so if both of those pass, they should work as expected here. + defParam $command 'Session' + } - New-JiraSession -Credential $testCredential - Get-JiraSession | Should Not BeNullOrEmpty + Context "Behavior testing" { + It "Closes a removes the JiraPS.Session data from module PrivateData" { + (Get-Module JiraPS).PrivateData = @{ Session = $true } + (Get-Module JiraPS).PrivateData.Session | Should -Not -BeNullOrEmpty Remove-JiraSession - Get-JiraSession | Should BeNullOrEmpty - } - - It "Correctly handles sessions from a variable" { - $Session = New-JiraSession -Credential $testCredential - $Session | Should Not BeNullOrEmpty - Get-JiraSession | Should Not BeNullOrEmpty - - Remove-JiraSession $Session - Get-JiraSession | Should BeNullOrEmpty - } - - It "Correctly handles pipeline input from New-JiraSession" { - { New-JiraSession -Credential $testCredential | Remove-JiraSession } | Should Not Throw - Get-JiraSession | Should BeNullOrEmpty - } - It "Correctly handles pipeline input from Get-JiraSession" { - New-JiraSession -Credential $testCredential - { Get-JiraSession | Remove-JiraSession } | Should Not Throw - Get-JiraSession | Should BeNullOrEmpty + (Get-Module JiraPS).PrivateData.Session | Should -BeNullOrEmpty } } } From 02103ecaa438e43f6b13086f7c61becb054daad1 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 19:29:25 +0200 Subject: [PATCH 69/83] Improved build script environemnt --- JiraPS.build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JiraPS.build.ps1 b/JiraPS.build.ps1 index 616d725c..dfdc47e2 100644 --- a/JiraPS.build.ps1 +++ b/JiraPS.build.ps1 @@ -289,7 +289,7 @@ task UpdateHomepage { #region Cleaning tasks # Synopsis: Clean the working dir -task Clean RemoveGeneratedFiles, RemoveTestResults, RemoveConfig +task Clean Init, RemoveGeneratedFiles, RemoveTestResults, RemoveConfig # Synopsis: Remove generated and temp files. task RemoveGeneratedFiles { From c136a104702af743441d376b66f26a7a19513dfc Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 19:30:00 +0200 Subject: [PATCH 70/83] Improved formatting of private functions --- JiraPS/Private/Join-Hashtable.ps1 | 8 ++-- .../Private/Resolve-DefaultParameterValue.ps1 | 37 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/JiraPS/Private/Join-Hashtable.ps1 b/JiraPS/Private/Join-Hashtable.ps1 index 5371b451..ada8d555 100644 --- a/JiraPS/Private/Join-Hashtable.ps1 +++ b/JiraPS/Private/Join-Hashtable.ps1 @@ -7,9 +7,6 @@ function Join-Hashtable { Combines multiple hashtables into a single table. On multiple identic keys, the last wins. - .PARAMETER Hashtable - The tables to merge. - .EXAMPLE PS C:\> Join-Hashtable -Hashtable $Hash1, $Hash2 @@ -17,7 +14,8 @@ function Join-Hashtable { #> [CmdletBinding()] Param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + # The tables to merge. + [Parameter( Mandatory, ValueFromPipeline )] [AllowNull()] [System.Collections.IDictionary[]] $Hashtable @@ -25,6 +23,7 @@ function Join-Hashtable { begin { $table = @{ } } + process { foreach ($item in $Hashtable) { foreach ($key in $item.Keys) { @@ -32,6 +31,7 @@ function Join-Hashtable { } } } + end { $table } diff --git a/JiraPS/Private/Resolve-DefaultParameterValue.ps1 b/JiraPS/Private/Resolve-DefaultParameterValue.ps1 index 781ccc94..5614ded2 100644 --- a/JiraPS/Private/Resolve-DefaultParameterValue.ps1 +++ b/JiraPS/Private/Resolve-DefaultParameterValue.ps1 @@ -8,19 +8,6 @@ function Resolve-DefaultParameterValue { It then filters all that match a specified command and binds them to that specific command, narrowing its focus. These get merged into either a new or a specified hashtable and returned. - .PARAMETER Reference - The hashtable to pick default parameter valeus from. - - .PARAMETER CommandName - The commands to pick default parameter values for. - - .PARAMETER Target - The target hashtable to merge results into. - By default an empty hashtable is used. - - .PARAMETER ParameterName - Only resolve for specific parameter names. - .EXAMPLE PS C:\> Resolve-DefaultParameterValue -Reference $global:PSDefaultParameterValues -CommandName 'Invoke-WebRequest' @@ -28,23 +15,29 @@ function Resolve-DefaultParameterValue { #> [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] + # The hashtable to pick default parameter valeus from. + [Parameter( Mandatory )] + [Hashtable] $Reference, - [Parameter(Mandatory = $true)] + # The commands to pick default parameter values for. + [Parameter( Mandatory )] [String[]] $CommandName, - [System.Collections.Hashtable] + # The target hashtable to merge results into. + # By default an empty hashtable is used. + [Hashtable] $Target = @{ }, + # Only resolve for specific parameter names. [String[]] $ParameterName = "*" ) begin { $defaultItems = New-Object -TypeName System.Collections.ArrayList + foreach ($key in $Reference.Keys) { $null = $defaultItems.Add( [PSCustomObject]@{ @@ -56,6 +49,7 @@ function Resolve-DefaultParameterValue { ) } } + process { foreach ($command in $CommandName) { foreach ($item in $defaultItems) { @@ -63,13 +57,18 @@ function Resolve-DefaultParameterValue { foreach ($parameter in $ParameterName) { if ($item.Parameter -like $parameter) { - if ($parameter -ne "*") { $Target["$($command):$($parameter)"] = $item.Value } - else { $Target["$($command):$($item.Parameter)"] = $item.Value } + if ($parameter -ne "*") { + $Target["$($command):$($parameter)"] = $item.Value + } + else { + $Target["$($command):$($item.Parameter)"] = $item.Value + } } } } } } + end { $Target } From 85a3db02fcd19ccd3817dd8af337d7cbceb63ebf Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 21:07:14 +0200 Subject: [PATCH 71/83] Added -Headers parameter to function's logic --- JiraPS/Public/New-JiraSession.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/JiraPS/Public/New-JiraSession.ps1 b/JiraPS/Public/New-JiraSession.ps1 index e13aaee8..660722ab 100644 --- a/JiraPS/Public/New-JiraSession.ps1 +++ b/JiraPS/Public/New-JiraSession.ps1 @@ -26,6 +26,7 @@ function New-JiraSession { $parameter = @{ URI = $resourceURi Method = "GET" + Headers = $Headers StoreSession = $true Credential = $Credential } From 02f33fa8fe7e7f0ae15ac10b41b15beb1570607b Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 21:07:37 +0200 Subject: [PATCH 72/83] Fixed filtering of Versions --- JiraPS/Public/Get-JiraVersion.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/JiraPS/Public/Get-JiraVersion.ps1 b/JiraPS/Public/Get-JiraVersion.ps1 index ecdce242..22e158c1 100644 --- a/JiraPS/Public/Get-JiraVersion.ps1 +++ b/JiraPS/Public/Get-JiraVersion.ps1 @@ -104,9 +104,11 @@ } Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter" - Invoke-JiraMethod @parameter | Where-Object { - $__ = $_ - Write-Verbose ($__ | out-string) + $result = Invoke-JiraMethod @parameter + + $result | Where-Object { + $__ = $_.Name + Write-DebugMessage ($__ | Out-String) $Name | Foreach-Object { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Matching $_ against $($__)" $__ -like $_ From f124eb005752e8fb3a2be2314b49defacba63034 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 21:08:42 +0200 Subject: [PATCH 73/83] Extracted name of ConvertTo-JiraSession function Moved name of ConvertTo-Session function to be a local variable of the module --- JiraPS/JiraPS.psm1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/JiraPS/JiraPS.psm1 b/JiraPS/JiraPS.psm1 index dbfdee3e..69f83146 100644 --- a/JiraPS/JiraPS.psm1 +++ b/JiraPS/JiraPS.psm1 @@ -25,9 +25,7 @@ if (!("System.Net.Http" -as [Type])) { #region Configuration $script:DefaultContentType = "application/json; charset=utf-8" $script:DefaultPageSize = 25 -$script:DefaultHeaders= @{ - "Accept-Charset" = "utf-8" -} +$script:DefaultHeaders= @{ "Accept-Charset" = "utf-8" } # Bug in PSv3's .Net API if ($PSVersionTable.PSVersion.Major -gt 3) { $script:DefaultHeaders["Accept"] = "application/json" @@ -40,6 +38,7 @@ $script:PagingContainers = @( "values" "worklogs" ) +$script:SessionTransformationMethod = "ConvertTo-JiraSession" #endregion Configuration #region LoadFunctions From d5400d39195320ec74f526ba3679c564210679a2 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Sun, 24 Jun 2018 21:09:14 +0200 Subject: [PATCH 74/83] Added proper tests for paging in Invoke-JiraMethod --- JiraPS/Public/Invoke-JiraMethod.ps1 | 23 +- Tests/Invoke-JiraMethod.Tests.ps1 | 937 ++++++++++++++++------------ 2 files changed, 566 insertions(+), 394 deletions(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 776179b7..3c935925 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -77,7 +77,7 @@ function Invoke-JiraMethod { #region Manage URI # Amend query from URI with GetParameter $uriQuery = ConvertTo-ParameterHash -Uri $Uri - $internalGetParameter = Join-Hashtable $GetParameter, $uriQuery + $internalGetParameter = Join-Hashtable $uriQuery, $GetParameter # And remove it from URI [Uri]$Uri = $Uri.GetLeftPart("Path") @@ -89,9 +89,11 @@ function Invoke-JiraMethod { } # Append GET parameters to URi + $offset = 0 if ($PSCmdlet.PagingParameters) { if ($PSCmdlet.PagingParameters.Skip) { $internalGetParameter["startAt"] = $PSCmdlet.PagingParameters.Skip + $offset = $PSCmdlet.PagingParameters.Skip } if ($PSCmdlet.PagingParameters.First -lt $internalGetParameter["maxResults"]) { $internalGetParameter["maxResults"] = $PSCmdlet.PagingParameters.First @@ -130,11 +132,6 @@ function Invoke-JiraMethod { } } - if ($StoreSession) { - $splatParameters["SessionVariable"] = "newSessionVar" - $splatParameters.Remove("WebSession") - } - if ((-not $Credential) -or ($Credential -eq [System.Management.Automation.PSCredential]::Empty)) { $splatParameters.Remove("Credential") if ($session = Get-JiraSession -ErrorAction SilentlyContinue) { @@ -142,6 +139,11 @@ function Invoke-JiraMethod { } } + if ($StoreSession) { + $splatParameters["SessionVariable"] = "newSessionVar" + $splatParameters.Remove("WebSession") + } + if ($InFile) { $splatParameters["InFile"] = $InFile } @@ -152,6 +154,7 @@ function Invoke-JiraMethod { #region Execute the actual query try { + Write-Debug ($splatParameters | Out-String) Write-Verbose "[$($MyInvocation.MyCommand.Name)] $($splatParameters.Method) $($splatParameters.Uri)" Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoke-WebRequest with `$splatParameters: $($splatParameters | Out-String)" # Invoke the API @@ -186,12 +189,14 @@ function Invoke-JiraMethod { #region Code 399- else { if ($StoreSession) { - return ConvertTo-JiraSession -Session $newSessionVar -Username $Credential.UserName + return & $script:SessionTransformationMethod -Session $newSessionVar -Username $Credential.UserName } if ($webResponse.Content) { $response = ConvertFrom-Json ([Text.Encoding]::UTF8.GetString($webResponse.RawContentStream.ToArray())) + Write-Debug ($response | Out-String) + if ($Paging) { # Remove Parameters that don't need propagation $script:PSDefaultParameterValues.Remove("$($MyInvocation.MyCommand.Name):IncludeTotalCount") @@ -211,7 +216,7 @@ function Invoke-JiraMethod { } } - $total += $result.Count + $total += @($result).Count Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] New total: $total" $pageSize = $response.maxResults Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] New pageSize: $pageSize" @@ -238,7 +243,7 @@ function Invoke-JiraMethod { # calculate the size of the next page Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] next page begins at $total" - $PSBoundParameters["GetParameter"]["startAt"] = $total + $PSBoundParameters["GetParameter"]["startAt"] = $total + $offset Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] doesn't it? $($PSBoundParameters["GetParameter"]["startAt"])" $expectedTotal = $PSBoundParameters["GetParameter"]["startAt"] + $pageSize Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] expecting to have $expectedTotal entries in total with next page" diff --git a/Tests/Invoke-JiraMethod.Tests.ps1 b/Tests/Invoke-JiraMethod.Tests.ps1 index 7cf78f1a..83829cb1 100644 --- a/Tests/Invoke-JiraMethod.Tests.ps1 +++ b/Tests/Invoke-JiraMethod.Tests.ps1 @@ -1,12 +1,90 @@ -Describe "Invoke-JiraMethod" { +[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] +param() - Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop +Describe "Invoke-JiraMethod" { + BeforeAll { + Remove-Module JiraPS -ErrorAction SilentlyContinue + Import-Module "$PSScriptRoot/../JiraPS" -Force -ErrorAction Stop + } + AfterEach { + # $script:ShowMockData = $false + } InModuleScope JiraPS { . "$PSScriptRoot/Shared.ps1" - $validMethods = @('GET', 'POST', 'PUT', 'DELETE') + #region Definitions + + $utf8String = "Lorem مرحبا Здравствуйте 😁" + $testUsername = 'testUsername' + $testPassword = ConvertTo-SecureString -AsPlainText -Force 'password123' + $testCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUsername, $testPassword + $pagedResponse1 = @" +{ + "startAt" : 0, + "maxResults" : 5, + "total": 7, + "issues": [ + { "id": 1 }, + { "id": 2 }, + { "id": 3 }, + { "id": 4 }, + { "id": 5 } + ] +} +"@ + $pagedResponse2 = @" +{ + "startAt" : 5, + "maxResults" : 5, + "total": 7, + "issues": [ + { "id": 6 }, + { "id": 7 } + ] +} +"@ + $pagedResponse3 = "{}" + $supportedTypes = @("JiraComment", "JiraIssue", "JiraUser", "JiraVersion") + #endregion Definitions + + #region Mocks + Mock Resolve-DefaultParameterValue -ModuleName JiraPS { @{ } } + Mock Join-Hashtable -ModuleName JiraPS { @{ } } + Mock Set-TlsLevel -ModuleName JiraPS { } + Mock Resolve-ErrorWebResponse -ModuleName JiraPS { } + Mock Get-JiraSession -ModuleName JiraPS { + [PSCustomObject]@{ + WebSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession + } + } + Mock Test-ServerResponse -Module JiraPS { } + Mock ConvertTo-JiraSession -ModuleName JiraPS { } + foreach ($type in $supportedTypes) { + Mock -CommandName "ConvertTo-$type" -ModuleName JiraPS { } + } + Mock Invoke-WebRequest -ModuleName JiraPS { + ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method', 'Body', 'Headers', 'ContentType', 'SessionVariable', 'WebSession' + $InvokeWebRequestSplat = @{ + Uri = $Uri + Method = $Method + Body = $Body + Headers = $Headers + WebSession = $WebSession + ContentType = $ContentType + } + if ($SessionVariable) { + $InvokeWebRequestSplat["SessionVariable"] = $SessionVariable + } + + Microsoft.PowerShell.Utility\Invoke-WebRequest @InvokeWebRequestSplat + + if ($SessionVariable) { + Set-Variable -Name $SessionVariable -Value (Get-Variable $SessionVariable).Value -Scope 3 # Pester adds 2 levels of nesting + } + } + #endregion Mocks Context "Sanity checking" { $command = Get-Command -Name Invoke-JiraMethod @@ -27,440 +105,529 @@ Describe "Invoke-JiraMethod" { It "Restricts the METHODs to WebRequestMethod" { $methodType = $command.Parameters.Method.ParameterType - $methodType.FullName | Should Be "Microsoft.PowerShell.Commands.WebRequestMethod" + $methodType.FullName | Should -Be "Microsoft.PowerShell.Commands.WebRequestMethod" } } Context "Behavior testing" { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] - - $testUri = 'http://example.com' - $testUsername = 'testUsername' - $testPassword = 'password123' - $testCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUsername, (ConvertTo-SecureString -AsPlainText -Force $testPassword) + It "uses Invoke-WebMethod under the hood" { + Invoke-JiraMethod -URI "https://postman-echo.com/get?test=123" -ErrorAction Stop - Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat } - It "Correctly performs all necessary HTTP method requests [$($validMethods -join ',')] to a provided URI" { - foreach ($method in $validMethods) { - { Invoke-JiraMethod -Method $method -URI $testUri } | Should Not Throw + It "parses a JSON response" { + $response = Invoke-JiraMethod -URI "https://postman-echo.com/get?test=123" -ErrorAction Stop - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$Method -eq $method -and $Uri -eq $testUri} -Scope It - } + $response | Should -BeOfType [PSCustomObject] } - It "Uses the -ContentType parameter of Invoke-WebRequest to specify application/json and UTF-8" { - { Invoke-JiraMethod -Method Get -URI $testUri } | Should Not Throw - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$ContentType -eq 'application/json; charset=utf-8'} -Scope It + It "resolves errors" { + Invoke-JiraMethod -URI "https://postman-echo.com/status/400" -ErrorAction Stop + + Assert-MockCalled -CommandName Resolve-ErrorWebResponse -ModuleName JiraPS -Exactly -Times 1 -Scope It } - It "Uses the -UseBasicParsing switch for Invoke-WebRequest" { - { Invoke-JiraMethod -Method Get -URI $testUri } | Should Not Throw - Assert-MockCalled -CommandName Invoke-WebRequest -ParameterFilter {$UseBasicParsing -eq $true} -Scope It + It "supports TLS1.2 connections" { + Invoke-JiraMethod -URI "https://postman-echo.com/get?test=123" -ErrorAction Stop + + Assert-MockCalled -CommandName Set-TlsLevel -ModuleName JiraPS -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Set-TlsLevel -ModuleName JiraPS -ParameterFilter {$Tls12 -eq $true} -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Set-TlsLevel -ModuleName JiraPS -ParameterFilter {$Revert -eq $true} -Exactly -Times 1 -Scope It } + It "uses global default values for parameters" { + Invoke-JiraMethod -URI "https://postman-echo.com/get?test=123" -ErrorAction Stop + + Assert-MockCalled -CommandName Resolve-DefaultParameterValue -ModuleName JiraPS -Exactly -Times 1 -Scope It + } } - $validTestUri = 'https://jira.atlassian.com/rest/api/latest/issue/303853' + Context "Input testing" { + It "parses a string to URi" { + [Uri]$Uri = "https://postman-echo.com/get?test=123" + $Uri | Should -BeOfType [Uri] - # This is a real REST result from Atlassian's public-facing JIRA instance, trimmed and cleaned - # up just a bit for fields we don't care about. + { Invoke-JiraMethod -URI "https://postman-echo.com/get?test=123" -ErrorAction Stop } | Should -Not -Throw + { Invoke-JiraMethod -URI $Uri -ErrorAction Stop } | Should -Not -Throw - # You can obtain this data with a single PowerShell line: - # Invoke-WebRequest -Method Get -Uri https://jira.atlassian.com/rest/api/latest/issue/303853 - $validRestResult = @' -{ - "expand": "renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations", - "id": "303853", - "self": "https://jira.atlassian.com/rest/api/latest/issue/303853", - "key": "DEMO-2719", - "fields": { - "issuetype": { - "self": "https://jira.atlassian.com/rest/api/2/issuetype/2", - "id": "2", - "description": "A new feature of the product, which has yet to be developed.", - "iconUrl": "https://jira.atlassian.com/images/icons/issuetypes/newfeature.png", - "name": "New Feature", - "subtask": false - }, - "timespent": null, - "project": { - "self": "https://jira.atlassian.com/rest/api/2/project/10820", - "id": "10820", - "key": "DEMO", - "name": "Demo", - "avatarUrls": { - "48x48": "https://jira.atlassian.com/secure/projectavatar?avatarId=10011", - "24x24": "https://jira.atlassian.com/secure/projectavatar?size=small&avatarId=10011", - "16x16": "https://jira.atlassian.com/secure/projectavatar?size=xsmall&avatarId=10011", - "32x32": "https://jira.atlassian.com/secure/projectavatar?size=medium&avatarId=10011" - } - }, - "fixVersions": [], - "aggregatetimespent": null, - "resolution": null, - "resolutiondate": null, - "workratio": -1, - "lastViewed": null, - "watches": { - "self": "https://jira.atlassian.com/rest/api/2/issue/DEMO-2719/watchers", - "watchCount": 1, - "isWatching": false - }, - "created": "2013-10-26T20:06:23.853+0000", - "priority": { - "self": "https://jira.atlassian.com/rest/api/2/priority/4", - "iconUrl": "https://jira.atlassian.com/images/icons/priorities/minor.png", - "name": "Minor", - "id": "4" - }, - "labels": [], - "aggregatetimeoriginalestimate": null, - "timeestimate": null, - "versions": [], - "issuelinks": [ - { - "id": "115932", - "self": "https://jira.atlassian.com/rest/api/2/issueLink/115932", - "type": { - "id": "10080", - "name": "Detail", - "inward": "is detailed by", - "outward": "details", - "self": "https://jira.atlassian.com/rest/api/2/issueLinkType/10080" - }, - "outwardIssue": { - "id": "303848", - "key": "DEMO-2717", - "self": "https://jira.atlassian.com/rest/api/2/issue/303848", - "fields": { - "summary": "New Feature Test Task", - "status": { - "self": "https://jira.atlassian.com/rest/api/2/status/1", - "description": "Issue is open and has not yet been accepted by Atlassian.", - "iconUrl": "https://jira.atlassian.com/images/icons/statuses/open.png", - "name": "Open", - "id": "1", - "statusCategory": { - "self": "https://jira.atlassian.com/rest/api/2/statuscategory/2", - "id": 2, - "key": "new", - "colorName": "blue-gray", - "name": "To Do" - } - }, - "priority": { - "self": "https://jira.atlassian.com/rest/api/2/priority/4", - "iconUrl": "https://jira.atlassian.com/images/icons/priorities/minor.png", - "name": "Minor", - "id": "4" - }, - "issuetype": { - "self": "https://jira.atlassian.com/rest/api/2/issuetype/2", - "id": "2", - "description": "A new feature of the product, which has yet to be developed.", - "iconUrl": "https://jira.atlassian.com/images/icons/issuetypes/newfeature.png", - "name": "New Feature", - "subtask": false + { Invoke-JiraMethod -URI "hello" -ErrorAction Stop } | Should -Throw + } + + foreach ($method in @('GET', 'POST', 'PUT', 'DELETE')) { + It "accepts [$method] as HTTP method" { + Invoke-JiraMethod -Method $method -URI "https://postman-echo.com/$method" + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $Method -eq $method } + Exactly = $true + Times = 1 + Scope = 'It' } + Assert-MockCalled @assertMockCalledSplat } - }, - { - "id": "119483", - "self": "https://jira.atlassian.com/rest/api/2/issueLink/119483", - "type": { - "id": "10000", - "name": "Reference", - "inward": "is related to", - "outward": "relates to", - "self": "https://jira.atlassian.com/rest/api/2/issueLinkType/10000" - }, - "outwardIssue": { - "id": "304302", - "key": "DEMO-2722", - "self": "https://jira.atlassian.com/rest/api/2/issue/304302", - "fields": { - "summary": "My summary", - "status": { - "self": "https://jira.atlassian.com/rest/api/2/status/1", - "description": "Issue is open and has not yet been accepted by Atlassian.", - "iconUrl": "https://jira.atlassian.com/images/icons/statuses/open.png", - "name": "Open", - "id": "1", - "statusCategory": { - "self": "https://jira.atlassian.com/rest/api/2/statuscategory/2", - "id": 2, - "key": "new", - "colorName": "blue-gray", - "name": "To Do" - } - }, - "priority": { - "self": "https://jira.atlassian.com/rest/api/2/priority/4", - "iconUrl": "https://jira.atlassian.com/images/icons/priorities/minor.png", - "name": "Minor", - "id": "4" - }, - "issuetype": { - "self": "https://jira.atlassian.com/rest/api/2/issuetype/1", - "id": "1", - "description": "A problem which impairs or prevents the functions of the product.", - "iconUrl": "https://jira.atlassian.com/images/icons/issuetypes/bug.png", - "name": "Bug", - "subtask": false - } + } + + It "encodes the Body with UTF-8 to support special chars" { + $invokeJiraMethodSplat = @{ + Method = 'Post' + URI = "https://postman-echo.com/post" + Body = $utf8String + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $Body -is [Byte[]] -and + ($Body -join " ") -eq "76 111 114 101 109 32 195 153 226 128 166 195 152 194 177 195 152 194 173 195 152 194 168 195 152 194 167 32 195 144 226 128 148 195 144 194 180 195 145 226 130 172 195 144 194 176 195 144 194 178 195 145 194 129 195 145 226 128 154 195 144 194 178 195 145 198 146 195 144 194 185 195 145 226 128 154 195 144 194 181 32 195 176 197 184 203 156 194 129" + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + + It "allows for skipping the UTF-8 encoding of the Body" { + $invokeJiraMethodSplat = @{ + Method = 'Post' + URI = "https://postman-echo.com/post" + Body = $utf8String + RawBody = $true + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $Body -is [String] -and + $Body -eq $utf8String + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + + It "overwrites module default headers with global PSDefaultParameterValues" {} + + It "overwrites global PSDefaultParameterValues with -Headers" {} + + It "overwrites module default headers with -Headers" {} + + It "overwrites get parameters in the URI with -GetParameter values" {} + + It "passes the -InFile to Invoke-WebRequest" { + $invokeJiraMethodSplat = @{ + Method = 'Post' + URI = "https://postman-echo.com/post" + InFile = "./file-does-not-exist.txt" + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $inFile -eq "./file-does-not-exist.txt" + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + + It "passes the -OutFile to Invoke-WebRequest" { + $invokeJiraMethodSplat = @{ + Method = 'Post' + URI = "https://postman-echo.com/post" + OutFile = "./file-does-not-exist.txt" + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $OutFile -eq "./file-does-not-exist.txt" + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + + It "uses ConvertTo-JiraSession to store the Session" { + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/get" + StoreSession = $true + ErrorAction = "Stop" + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = "Invoke-WebRequest" + ModuleName = 'JiraPS' + ParameterFilter = {$SessionVariable -eq "newSessionVar"} + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + Assert-MockCalled -CommandName ConvertTo-JiraSession -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + foreach ($type in $supportedTypes) { + It "uses ConvertTo-$type to transform the results" { + Invoke-JiraMethod -Method get -URI "https://postman-echo.com/get" -OutputType $type -Paging -ErrorAction Stop + + Assert-MockCalled -CommandName "ConvertTo-$type" -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "only uses -OutputType with -Paging [$type]" { + Invoke-JiraMethod -Method get -URI "https://postman-echo.com/get" -OutputType $type -ErrorAction Stop + + Assert-MockCalled -CommandName "ConvertTo-$type" -ModuleName JiraPS -Exactly -Times 0 -Scope It + } + } + + It "uses session if no -Credential are passed" { + $invokeJiraMethodSplat = @{ + URI = "https://postman-echo.com/get" + Method = 'get' + ErrorAction = "Stop" + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $WebSession -is [Microsoft.PowerShell.Commands.WebRequestSession] -and + $Credential -eq $null + } + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + Assert-MockCalled -CommandName Get-JiraSession -ModuleName JiraPS -Exactly -Times 1 -Scope It + } + + It "uses -Credential even if session is present" { + Mock Get-JiraSession -ModuleName JiraPS { + [PSCustomObject]@{ + WebSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession + } + } + + $invokeJiraMethodSplat = @{ + URI = "https://postman-echo.com/get" + Method = 'get' + Credential = $testCred + ErrorAction = "Stop" + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + ParameterFilter = { + $SessionVariable -eq $null -and + $Credential -ne $null } + Exactly = $true + Times = 1 + Scope = 'It' } - }, - { - "id": "115931", - "self": "https://jira.atlassian.com/rest/api/2/issueLink/115931", - "type": { - "id": "10000", - "name": "Reference", - "inward": "is related to", - "outward": "relates to", - "self": "https://jira.atlassian.com/rest/api/2/issueLinkType/10000" - }, - "inwardIssue": { - "id": "303852", - "key": "DEMO-2718", - "self": "https://jira.atlassian.com/rest/api/2/issue/303852", - "fields": { - "summary": "REST ye merry gentlemen.", - "status": { - "self": "https://jira.atlassian.com/rest/api/2/status/1", - "description": "Issue is open and has not yet been accepted by Atlassian.", - "iconUrl": "https://jira.atlassian.com/images/icons/statuses/open.png", - "name": "Open", - "id": "1", - "statusCategory": { - "self": "https://jira.atlassian.com/rest/api/2/statuscategory/2", - "id": 2, - "key": "new", - "colorName": "blue-gray", - "name": "To Do" - } - }, - "priority": { - "self": "https://jira.atlassian.com/rest/api/2/priority/4", - "iconUrl": "https://jira.atlassian.com/images/icons/priorities/minor.png", - "name": "Minor", - "id": "4" - }, - "issuetype": { - "self": "https://jira.atlassian.com/rest/api/2/issuetype/2", - "id": "2", - "description": "A new feature of the product, which has yet to be developed.", - "iconUrl": "https://jira.atlassian.com/images/icons/issuetypes/newfeature.png", - "name": "New Feature", - "subtask": false + Assert-MockCalled @assertMockCalledSplat + Assert-MockCalled -CommandName Get-JiraSession -ModuleName JiraPS -Exactly -Times 0 -Scope It + } + + It "uses -Headers for the call" { + Mock Join-Hashtable -ModuleName JiraPS { + $table = @{ } + foreach ($item in $Hashtable) { + foreach ($key in $item.Keys) { + $table[$key] = $item[$key] } } + $table + } + + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/headers" + Headers = @{ + "X-Fake" = "lorem ipsum" + } + ErrorAction = "Stop" + } + $defaultResponse = Invoke-JiraMethod @invokeJiraMethodSplat + + $invokeJiraMethodSplat["Headers"] = @{ + "X-Fake" = "dolor sum" + } + $changedResponse = Invoke-JiraMethod @invokeJiraMethodSplat + + $defaultResponse.headers."x-fake" | Should -Be "lorem ipsum" + $changedResponse.headers."x-fake" | Should -Be "dolor sum" + + $assertMockCalledSplat = @{ + CommandName = "Invoke-WebRequest" + ModuleName = 'JiraPS' + Exactly = $true + Times = 2 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat + } + + It "uses authenticates as anonymous when no -Credential is provided and no session exists" -pending { + Mock Get-JiraSession -ModuleName JiraPS { + $null + } + + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/headers" + ErrorAction = "Stop" + } + Invoke-JiraMethod @invokeJiraMethodSplat + + $assertMockCalledSplat = @{ + CommandName = "Invoke-WebRequest" + ModuleName = 'JiraPS' + ParameterFilter = { + $Credential -eq $null -and + $WebSession -eq $null + } + Exactly = $true + Times = 2 + Scope = 'It' } + Assert-MockCalled @assertMockCalledSplat } - ], - "assignee": { - "self": "https://jira.atlassian.com/rest/api/2/user?username=ben%40atlassian.com", - "name": "ben@atlassian.com", - "key": "ben@atlassian.com", - "emailAddress": "ben at atlassian dot com", - "avatarUrls": { - "48x48": "https://jira.atlassian.com/secure/useravatar?ownerId=ben%40atlassian.com&avatarId=72204", - "24x24": "https://jira.atlassian.com/secure/useravatar?size=small&ownerId=ben%40atlassian.com&avatarId=72204", - "16x16": "https://jira.atlassian.com/secure/useravatar?size=xsmall&ownerId=ben%40atlassian.com&avatarId=72204", - "32x32": "https://jira.atlassian.com/secure/useravatar?size=medium&ownerId=ben%40atlassian.com&avatarId=72204" - }, - "displayName": "Benjamin Naftzger [Atlassian]", - "active": true, - "timeZone": "Europe/Berlin" - }, - "updated": "2013-12-08T11:00:43.133+0000", - "status": { - "self": "https://jira.atlassian.com/rest/api/2/status/1", - "description": "Issue is open and has not yet been accepted by Atlassian.", - "iconUrl": "https://jira.atlassian.com/images/icons/statuses/open.png", - "name": "Open", - "id": "1", - "statusCategory": { - "self": "https://jira.atlassian.com/rest/api/2/statuscategory/2", - "id": 2, - "key": "new", - "colorName": "blue-gray", - "name": "To Do" - } - }, - "components": [], - "timeoriginalestimate": null, - "description": "Creating of an issue using project keys and issue type names using the REST API", - "timetracking": {}, - "attachment": [], - "aggregatetimeestimate": null, - "summary": "REST ye merry gentlemen.", - "creator": { - "self": "https://jira.atlassian.com/rest/api/2/user?username=gokhant", - "name": "gokhant", - "key": "gokhant", - "emailAddress": "gokhant at gmail dot com", - "avatarUrls": { - "48x48": "https://jira.atlassian.com/secure/useravatar?ownerId=gokhant&avatarId=73000", - "24x24": "https://jira.atlassian.com/secure/useravatar?size=small&ownerId=gokhant&avatarId=73000", - "16x16": "https://jira.atlassian.com/secure/useravatar?size=xsmall&ownerId=gokhant&avatarId=73000", - "32x32": "https://jira.atlassian.com/secure/useravatar?size=medium&ownerId=gokhant&avatarId=73000" - }, - "displayName": "Gokhan Tuna", - "active": true, - "timeZone": "Etc/UTC" - }, - "subtasks": [], - "reporter": { - "self": "https://jira.atlassian.com/rest/api/2/user?username=gokhant", - "name": "gokhant", - "key": "gokhant", - "emailAddress": "gokhant at gmail dot com", - "avatarUrls": { - "48x48": "https://jira.atlassian.com/secure/useravatar?ownerId=gokhant&avatarId=73000", - "24x24": "https://jira.atlassian.com/secure/useravatar?size=small&ownerId=gokhant&avatarId=73000", - "16x16": "https://jira.atlassian.com/secure/useravatar?size=xsmall&ownerId=gokhant&avatarId=73000", - "32x32": "https://jira.atlassian.com/secure/useravatar?size=medium&ownerId=gokhant&avatarId=73000" - }, - "displayName": "Gokhan Tuna", - "active": true, - "timeZone": "Etc/UTC" - }, - "aggregateprogress": { - "progress": 0, - "total": 0 - }, - "environment": null, - "duedate": null, - "progress": { - "progress": 0, - "total": 0 - }, - "comment": { - "startAt": 0, - "maxResults": 1, - "total": 1, - "comments": [ - { - "self": "https://jira.atlassian.com/rest/api/2/issue/303853/comment/534625", - "id": "534625", - "author": { - "self": "https://jira.atlassian.com/rest/api/2/user?username=gokhant", - "name": "gokhant", - "key": "gokhant", - "emailAddress": "gokhant at gmail dot com", - "avatarUrls": { - "48x48": "https://jira.atlassian.com/secure/useravatar?ownerId=gokhant&avatarId=73000", - "24x24": "https://jira.atlassian.com/secure/useravatar?size=small&ownerId=gokhant&avatarId=73000", - "16x16": "https://jira.atlassian.com/secure/useravatar?size=xsmall&ownerId=gokhant&avatarId=73000", - "32x32": "https://jira.atlassian.com/secure/useravatar?size=medium&ownerId=gokhant&avatarId=73000" - }, - "displayName": "Gokhan Tuna", - "active": true, - "timeZone": "Etc/UTC" - }, - "body": "test comment", - "updateAuthor": { - "self": "https://jira.atlassian.com/rest/api/2/user?username=gokhant", - "name": "gokhant", - "key": "gokhant", - "emailAddress": "gokhant at gmail dot com", - "avatarUrls": { - "48x48": "https://jira.atlassian.com/secure/useravatar?ownerId=gokhant&avatarId=73000", - "24x24": "https://jira.atlassian.com/secure/useravatar?size=small&ownerId=gokhant&avatarId=73000", - "16x16": "https://jira.atlassian.com/secure/useravatar?size=xsmall&ownerId=gokhant&avatarId=73000", - "32x32": "https://jira.atlassian.com/secure/useravatar?size=medium&ownerId=gokhant&avatarId=73000" - }, - "displayName": "Gokhan Tuna", - "active": true, - "timeZone": "Etc/UTC" - }, - "created": "2013-11-05T02:50:09.991+0000", - "updated": "2013-11-05T02:50:09.991+0000" - } - ] - }, - "votes": { - "self": "https://jira.atlassian.com/rest/api/2/issue/DEMO-2719/votes", - "votes": 0, - "hasVoted": false - }, - "worklog": { - "startAt": 0, - "maxResults": 20, - "total": 0, - "worklogs": [] - } - } -} -'@ - $validObjResult = ConvertFrom-Json -InputObject $validRestResult + It "removes and content-type from headers and uses Invoke-WebRequest's -ContentType" { + Mock Join-Hashtable -ModuleName JiraPS { + $table = @{ } + foreach ($item in $Hashtable) { + foreach ($key in $item.Keys) { + $table[$key] = $item[$key] + } + } + $table + } + + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/headers" + ErrorAction = "Stop" + } + $defaultResponse = Invoke-JiraMethod @invokeJiraMethodSplat - Context "Output handling - valid object returned (HTTP 200)" { + $invokeJiraMethodSplat["Headers"] = @{ + "Content-Type" = "text/plain" + } + $changedResponse = Invoke-JiraMethod @invokeJiraMethodSplat - It "Outputs an object representation of JSON returned from JIRA" { + $defaultResponse.headers."content-type" | Should -Be "application/json; charset=utf-8" + $changedResponse.headers."content-type" | Should -Be "text/plain" - Mock Invoke-WebRequest -ParameterFilter {$Method -eq 'Get' -and $Uri -eq $validTestUri} { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' - Write-Output [PSCustomObject] @{ - 'Content' = $validRestResult + $assertMockCalledSplat = @{ + CommandName = "Invoke-WebRequest" + ModuleName = 'JiraPS' + ParameterFilter = { + $Uri -notlike "*contentType*" -and + $Uri -notlike "*content-Type*" -and + $ContentType -eq "application/json; charset=utf-8" } + Exactly = $true + Times = 1 + Scope = 'It' } + Assert-MockCalled @assertMockCalledSplat - $result = Invoke-JiraMethod -Method Get -URI $validTestUri - $result | Should Not BeNullOrEmpty + $assertMockCalledSplat["ParameterFilter"] = { + $Uri -notlike "*contentType*" -and + $Uri -notlike "*content-Type*" -and + $ContentType -eq "text/plain" + } + Assert-MockCalled @assertMockCalledSplat + } - # Compare each property in the result returned to the expected result - foreach ($property in (Get-Member -InputObject $result | Where-Object {$_.MemberType -eq 'NoteProperty'})) { - $result.$property | Should Be $validObjResult.$property + It "can handle UTF-8 chars in the response" { + $invokeJiraMethodSplat = @{ + Method = 'Post' + URI = "https://postman-echo.com/post" + Body = $utf8String + ErrorAction = "Stop" } + $response = Invoke-JiraMethod @invokeJiraMethodSplat + + $response.data | Should -Be $utf8String } } - Context "Output handling - no content returned (HTTP 204)" { - Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' + Context "Paged restuls" { + Mock Invoke-WebRequest -ModuleName JiraPS { + ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method', 'Body' + + $response = "" + if ($Uri -match "startAt\=(\d+)") { + switch ($matches[1]) { + 5 {$response = $pagedResponse2; break } + 7 { $response = $pagedResponse3; break } + } + } + if (-not $response) { + $response = $pagedResponse1 + } + + $InvokeWebRequestSplat = @{ + Uri = "https://postman-echo.com/post" + Method = "Post" + Body = $response + } + $result = Microsoft.PowerShell.Utility\Invoke-WebRequest @InvokeWebRequestSplat + + $scriptBlock = "`$response = @`"`n$response`n`"@;Write-Output ([System.Text.Encoding]::UTF8.GetBytes(`$response))" + $result.RawContentStream | Add-Member -MemberType ScriptMethod -Name "ToArray" -Force -Value ([Scriptblock]::Create($scriptBlock)) + $result + } + Mock Join-Hashtable -ModuleName JiraPS { + $table = @{ } + foreach ($item in $Hashtable) { + foreach ($key in $item.Keys) { + $table[$key] = $item[$key] + } + } + $table + } + + It "requests each page of the results" { + { + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/Get" + Paging = $true + ErrorAction = "Stop" + } + Invoke-JiraMethod @invokeJiraMethodSplat + } | Should -Not -Throw - Write-Output [PSCustomObject] @{ - 'StatusCode' = 204 - 'Content' = $null + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + Exactly = $true + Times = 3 + Scope = 'It' } + Assert-MockCalled @assertMockCalledSplat } - Mock ConvertFrom-Json { - ShowMockInfo 'ConvertFrom-Json' + + It "expands the data container" { + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/Get" + Paging = $true + ErrorAction = "Stop" + } + $result = Invoke-JiraMethod @invokeJiraMethodSplat + + $result.Count | Should -Be 7 + + { $result | Get-Member -Name Id } | Should -Not -Throw + { $result | Get-Member -Name Id } | Should -Not -BeNullOrEmpty } - It "Correctly handles HTTP response codes that do not provide a return body" { - { Invoke-JiraMethod -Method Get -URI $validTestUri } | Should Not Throw - Assert-MockCalled -CommandName ConvertFrom-Json -Exactly -Times 0 -Scope It + It "fetches only the necessary amount of pages when -First is used" { + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/Get" + Paging = $true + First = 4 + ErrorAction = "Stop" + } + $result = Invoke-JiraMethod @invokeJiraMethodSplat + + $result.Count | Should -Be 4 + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + Exactly = $true + Times = 1 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat } - } - Context "Output handling - JIRA error returned (HTTP 400 and up)" { - $invalidTestUri = 'https://jira.atlassian.com/rest/api/latest/issue/1' - $invalidRestResult = '{"errorMessages":["Issue Does Not Exist"],"errors":{}}' + It "limits the number of results when -First is used" { + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/Get" + Paging = $true + First = 6 + ErrorAction = "Stop" + } + $result = Invoke-JiraMethod @invokeJiraMethodSplat + + $result.Count | Should -Be 6 - Mock Invoke-WebRequest { - ShowMockInfo 'Invoke-WebRequest' -Params 'Uri', 'Method' - Write-Output [PSCustomObject] @{ - 'StatusCode' = 400 - 'Content' = $invalidRestResult + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + Exactly = $true + Times = 2 + Scope = 'It' } + Assert-MockCalled @assertMockCalledSplat } - Mock Resolve-JiraError { - ShowMockInfo 'Resolve-JiraError' -params 'InputObject' + It "starts looking for results with an offset when -Skip is provided" { + $invokeJiraMethodSplat = @{ + Method = 'Get' + URI = "https://postman-echo.com/Get" + Paging = $true + Skip = 5 + ErrorAction = "Stop" + } + $result = Invoke-JiraMethod @invokeJiraMethodSplat + + $result.Count | Should -Be 2 + + $assertMockCalledSplat = @{ + CommandName = 'Invoke-WebRequest' + ModuleName = 'JiraPS' + Exactly = $true + Times = 2 + Scope = 'It' + } + Assert-MockCalled @assertMockCalledSplat } - It "Uses Resolve-JiraError to parse any JIRA error messages returned" { - { Invoke-JiraMethod -Method Get -URI $invalidTestUri } | Should Not Throw - Assert-MockCalled -CommandName Resolve-JiraError -Exactly -Times 1 -Scope It + It "-totalcount" { + # Don't know how to test this } } } From 0779243cc1b6c7db75eaa50e359c21c6be112a88 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 25 Jun 2018 13:15:09 +0200 Subject: [PATCH 75/83] Fixed tests on PSv6 --- Tests/Invoke-JiraMethod.Tests.ps1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/Invoke-JiraMethod.Tests.ps1 b/Tests/Invoke-JiraMethod.Tests.ps1 index 83829cb1..a72639a9 100644 --- a/Tests/Invoke-JiraMethod.Tests.ps1 +++ b/Tests/Invoke-JiraMethod.Tests.ps1 @@ -192,7 +192,8 @@ Describe "Invoke-JiraMethod" { ModuleName = 'JiraPS' ParameterFilter = { $Body -is [Byte[]] -and - ($Body -join " ") -eq "76 111 114 101 109 32 195 153 226 128 166 195 152 194 177 195 152 194 173 195 152 194 168 195 152 194 167 32 195 144 226 128 148 195 144 194 180 195 145 226 130 172 195 144 194 176 195 144 194 178 195 145 194 129 195 145 226 128 154 195 144 194 178 195 145 198 146 195 144 194 185 195 145 226 128 154 195 144 194 181 32 195 176 197 184 203 156 194 129" + (($Body -join " ") -eq "76 111 114 101 109 32 195 153 226 128 166 195 152 194 177 195 152 194 173 195 152 194 168 195 152 194 167 32 195 144 226 128 148 195 144 194 180 195 145 226 130 172 195 144 194 176 195 144 194 178 195 145 194 129 195 145 226 128 154 195 144 194 178 195 145 198 146 195 144 194 185 195 145 226 128 154 195 144 194 181 32 195 176 197 184 203 156 194 129" -or + ($Body -join " ") -eq "76 111 114 101 109 32 217 133 216 177 216 173 216 168 216 167 32 208 151 208 180 209 128 208 176 208 178 209 129 209 130 208 178 209 131 208 185 209 130 208 181 32 240 159 152 129") } Exactly = $true Times = 1 @@ -450,9 +451,6 @@ Describe "Invoke-JiraMethod" { } $changedResponse = Invoke-JiraMethod @invokeJiraMethodSplat - $defaultResponse.headers."content-type" | Should -Be "application/json; charset=utf-8" - $changedResponse.headers."content-type" | Should -Be "text/plain" - $assertMockCalledSplat = @{ CommandName = "Invoke-WebRequest" ModuleName = 'JiraPS' From 298dce5ba8282608b79fccb2a0c9d4f60d63f301 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 25 Jun 2018 18:24:40 +0200 Subject: [PATCH 76/83] Fixed external help for PSv3 --- JiraPS/Public/Add-JiraFilterPermission.ps1 | 1 + JiraPS/Public/Add-JiraGroupMember.ps1 | 1 + JiraPS/Public/Add-JiraIssueAttachment.ps1 | 1 + JiraPS/Public/Add-JiraIssueComment.ps1 | 1 + JiraPS/Public/Add-JiraIssueLink.ps1 | 1 + JiraPS/Public/Add-JiraIssueWatcher.ps1 | 1 + JiraPS/Public/Add-JiraIssueWorklog.ps1 | 1 + JiraPS/Public/Format-Jira.ps1 | 1 + JiraPS/Public/Get-JiraComponent.ps1 | 1 + JiraPS/Public/Get-JiraConfigServer.ps1 | 1 + JiraPS/Public/Get-JiraField.ps1 | 1 + JiraPS/Public/Get-JiraFilter.ps1 | 1 + JiraPS/Public/Get-JiraFilterPermission.ps1 | 1 + JiraPS/Public/Get-JiraGroup.ps1 | 1 + JiraPS/Public/Get-JiraGroupMember.ps1 | 1 + JiraPS/Public/Get-JiraIssue.ps1 | 1 + JiraPS/Public/Get-JiraIssueAttachment.ps1 | 1 + JiraPS/Public/Get-JiraIssueComment.ps1 | 1 + JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 | 1 + JiraPS/Public/Get-JiraIssueEditMetadata.ps1 | 1 + JiraPS/Public/Get-JiraIssueLink.ps1 | 1 + JiraPS/Public/Get-JiraIssueLinkType.ps1 | 1 + JiraPS/Public/Get-JiraIssueType.ps1 | 1 + JiraPS/Public/Get-JiraIssueWatcher.ps1 | 1 + JiraPS/Public/Get-JiraPriority.ps1 | 1 + JiraPS/Public/Get-JiraProject.ps1 | 1 + JiraPS/Public/Get-JiraRemoteLink.ps1 | 1 + JiraPS/Public/Get-JiraServerInformation.ps1 | 1 + JiraPS/Public/Get-JiraSession.ps1 | 1 + JiraPS/Public/Get-JiraUser.ps1 | 1 + JiraPS/Public/Get-JiraVersion.ps1 | 1 + JiraPS/Public/Invoke-JiraIssueTransition.ps1 | 1 + JiraPS/Public/New-JiraFilter.ps1 | 1 + JiraPS/Public/New-JiraGroup.ps1 | 1 + JiraPS/Public/New-JiraIssue.ps1 | 1 + JiraPS/Public/New-JiraSession.ps1 | 1 + JiraPS/Public/New-JiraUser.ps1 | 1 + JiraPS/Public/New-JiraVersion.ps1 | 1 + JiraPS/Public/Remove-JiraFilter.ps1 | 1 + JiraPS/Public/Remove-JiraFilterPermission.ps1 | 1 + JiraPS/Public/Remove-JiraGroup.ps1 | 1 + JiraPS/Public/Remove-JiraGroupMember.ps1 | 1 + JiraPS/Public/Remove-JiraIssue.ps1 | 1 + JiraPS/Public/Remove-JiraIssueAttachment.ps1 | 1 + JiraPS/Public/Remove-JiraIssueLink.ps1 | 1 + JiraPS/Public/Remove-JiraIssueWatcher.ps1 | 1 + JiraPS/Public/Remove-JiraRemoteLink.ps1 | 1 + JiraPS/Public/Remove-JiraSession.ps1 | 1 + JiraPS/Public/Remove-JiraUser.ps1 | 1 + JiraPS/Public/Remove-JiraVersion.ps1 | 1 + JiraPS/Public/Set-JiraConfigServer.ps1 | 1 + JiraPS/Public/Set-JiraFilter.ps1 | 1 + JiraPS/Public/Set-JiraIssue.ps1 | 1 + JiraPS/Public/Set-JiraIssueLabel.ps1 | 1 + JiraPS/Public/Set-JiraUser.ps1 | 1 + JiraPS/Public/Set-JiraVersion.ps1 | 1 + 56 files changed, 56 insertions(+) diff --git a/JiraPS/Public/Add-JiraFilterPermission.ps1 b/JiraPS/Public/Add-JiraFilterPermission.ps1 index 6e2ca439..74dc3de4 100644 --- a/JiraPS/Public/Add-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Add-JiraFilterPermission.ps1 @@ -1,4 +1,5 @@ function Add-JiraFilterPermission { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ByInputObject' )] # [OutputType( [JiraPS.FilterPermission] )] param( diff --git a/JiraPS/Public/Add-JiraGroupMember.ps1 b/JiraPS/Public/Add-JiraGroupMember.ps1 index fd96f8bd..7287f39e 100644 --- a/JiraPS/Public/Add-JiraGroupMember.ps1 +++ b/JiraPS/Public/Add-JiraGroupMember.ps1 @@ -1,4 +1,5 @@ function Add-JiraGroupMember { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Add-JiraIssueAttachment.ps1 b/JiraPS/Public/Add-JiraIssueAttachment.ps1 index 29a2e949..72756b16 100644 --- a/JiraPS/Public/Add-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Add-JiraIssueAttachment.ps1 @@ -1,4 +1,5 @@ function Add-JiraIssueAttachment { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Add-JiraIssueComment.ps1 b/JiraPS/Public/Add-JiraIssueComment.ps1 index 50032816..5b99915c 100644 --- a/JiraPS/Public/Add-JiraIssueComment.ps1 +++ b/JiraPS/Public/Add-JiraIssueComment.ps1 @@ -1,4 +1,5 @@ function Add-JiraIssueComment { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Add-JiraIssueLink.ps1 b/JiraPS/Public/Add-JiraIssueLink.ps1 index c5770ef9..1a1dbf9a 100644 --- a/JiraPS/Public/Add-JiraIssueLink.ps1 +++ b/JiraPS/Public/Add-JiraIssueLink.ps1 @@ -1,4 +1,5 @@ function Add-JiraIssueLink { +# .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Add-JiraIssueWatcher.ps1 b/JiraPS/Public/Add-JiraIssueWatcher.ps1 index 323eb526..fb930288 100644 --- a/JiraPS/Public/Add-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Add-JiraIssueWatcher.ps1 @@ -1,4 +1,5 @@ function Add-JiraIssueWatcher { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Add-JiraIssueWorklog.ps1 b/JiraPS/Public/Add-JiraIssueWorklog.ps1 index c8ee9b28..edb067a2 100644 --- a/JiraPS/Public/Add-JiraIssueWorklog.ps1 +++ b/JiraPS/Public/Add-JiraIssueWorklog.ps1 @@ -1,4 +1,5 @@ function Add-JiraIssueWorklog { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Format-Jira.ps1 b/JiraPS/Public/Format-Jira.ps1 index 58e2d257..2d01b244 100644 --- a/JiraPS/Public/Format-Jira.ps1 +++ b/JiraPS/Public/Format-Jira.ps1 @@ -1,4 +1,5 @@ function Format-Jira { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] [OutputType([System.String])] param( diff --git a/JiraPS/Public/Get-JiraComponent.ps1 b/JiraPS/Public/Get-JiraComponent.ps1 index 7b58099a..4374669b 100644 --- a/JiraPS/Public/Get-JiraComponent.ps1 +++ b/JiraPS/Public/Get-JiraComponent.ps1 @@ -1,4 +1,5 @@ function Get-JiraComponent { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding(DefaultParameterSetName = 'ByID')] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByProject' )] diff --git a/JiraPS/Public/Get-JiraConfigServer.ps1 b/JiraPS/Public/Get-JiraConfigServer.ps1 index 297a114f..36b5bd87 100644 --- a/JiraPS/Public/Get-JiraConfigServer.ps1 +++ b/JiraPS/Public/Get-JiraConfigServer.ps1 @@ -1,4 +1,5 @@ function Get-JiraConfigServer { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] [OutputType([System.String])] param( diff --git a/JiraPS/Public/Get-JiraField.ps1 b/JiraPS/Public/Get-JiraField.ps1 index 1ec24eff..fd55df9f 100644 --- a/JiraPS/Public/Get-JiraField.ps1 +++ b/JiraPS/Public/Get-JiraField.ps1 @@ -1,4 +1,5 @@ function Get-JiraField { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = '_All' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = '_Search' )] diff --git a/JiraPS/Public/Get-JiraFilter.ps1 b/JiraPS/Public/Get-JiraFilter.ps1 index 2a7789b4..412c161c 100644 --- a/JiraPS/Public/Get-JiraFilter.ps1 +++ b/JiraPS/Public/Get-JiraFilter.ps1 @@ -1,4 +1,5 @@ function Get-JiraFilter { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding(DefaultParameterSetName = 'ByFilterID')] param( [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByFilterID' )] diff --git a/JiraPS/Public/Get-JiraFilterPermission.ps1 b/JiraPS/Public/Get-JiraFilterPermission.ps1 index bc8fc4f6..4f04f707 100644 --- a/JiraPS/Public/Get-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Get-JiraFilterPermission.ps1 @@ -1,4 +1,5 @@ function Get-JiraFilterPermission { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = 'ById' )] # [OutputType( [JiraPS.FilterPermission] )] param( diff --git a/JiraPS/Public/Get-JiraGroup.ps1 b/JiraPS/Public/Get-JiraGroup.ps1 index 7a689da1..dc4e395e 100644 --- a/JiraPS/Public/Get-JiraGroup.ps1 +++ b/JiraPS/Public/Get-JiraGroup.ps1 @@ -1,4 +1,5 @@ function Get-JiraGroup { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraGroupMember.ps1 b/JiraPS/Public/Get-JiraGroupMember.ps1 index aad482ba..0ffe0579 100644 --- a/JiraPS/Public/Get-JiraGroupMember.ps1 +++ b/JiraPS/Public/Get-JiraGroupMember.ps1 @@ -1,4 +1,5 @@ function Get-JiraGroupMember { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsPaging )] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 2bc98c8f..92279054 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssue { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsPaging, DefaultParameterSetName = 'ByIssueKey' )] param( [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByIssueKey' )] diff --git a/JiraPS/Public/Get-JiraIssueAttachment.ps1 b/JiraPS/Public/Get-JiraIssueAttachment.ps1 index b766a7d9..cf833b16 100644 --- a/JiraPS/Public/Get-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Get-JiraIssueAttachment.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueAttachment { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraIssueComment.ps1 b/JiraPS/Public/Get-JiraIssueComment.ps1 index 49ef28b4..24956cd3 100644 --- a/JiraPS/Public/Get-JiraIssueComment.ps1 +++ b/JiraPS/Public/Get-JiraIssueComment.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueComment { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 b/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 index 38bd086e..f1a03ab0 100644 --- a/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 +++ b/JiraPS/Public/Get-JiraIssueCreateMetadata.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueCreateMetadata { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 b/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 index 7bbfac7a..a44655c6 100644 --- a/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 +++ b/JiraPS/Public/Get-JiraIssueEditMetadata.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueEditMetadata { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Get-JiraIssueLink.ps1 b/JiraPS/Public/Get-JiraIssueLink.ps1 index dbe9eb5c..36959a52 100644 --- a/JiraPS/Public/Get-JiraIssueLink.ps1 +++ b/JiraPS/Public/Get-JiraIssueLink.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueLink { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraIssueLinkType.ps1 b/JiraPS/Public/Get-JiraIssueLinkType.ps1 index c6205061..0ca0d39a 100644 --- a/JiraPS/Public/Get-JiraIssueLinkType.ps1 +++ b/JiraPS/Public/Get-JiraIssueLinkType.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueLinkType { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = '_All' )] param( [Parameter( Position = 0, Mandatory, ParameterSetName = '_Search' )] diff --git a/JiraPS/Public/Get-JiraIssueType.ps1 b/JiraPS/Public/Get-JiraIssueType.ps1 index 70cea3ea..41df6832 100644 --- a/JiraPS/Public/Get-JiraIssueType.ps1 +++ b/JiraPS/Public/Get-JiraIssueType.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueType { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = '_All' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = '_Search' )] diff --git a/JiraPS/Public/Get-JiraIssueWatcher.ps1 b/JiraPS/Public/Get-JiraIssueWatcher.ps1 index d8ca1ab4..2d671933 100644 --- a/JiraPS/Public/Get-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Get-JiraIssueWatcher.ps1 @@ -1,4 +1,5 @@ function Get-JiraIssueWatcher { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraPriority.ps1 b/JiraPS/Public/Get-JiraPriority.ps1 index 311d9a07..441c1bf4 100644 --- a/JiraPS/Public/Get-JiraPriority.ps1 +++ b/JiraPS/Public/Get-JiraPriority.ps1 @@ -1,4 +1,5 @@ function Get-JiraPriority { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = '_All' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = '_Search' )] diff --git a/JiraPS/Public/Get-JiraProject.ps1 b/JiraPS/Public/Get-JiraProject.ps1 index 6cf06f30..c107663b 100644 --- a/JiraPS/Public/Get-JiraProject.ps1 +++ b/JiraPS/Public/Get-JiraProject.ps1 @@ -1,4 +1,5 @@ function Get-JiraProject { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = '_All' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = '_Search' )] diff --git a/JiraPS/Public/Get-JiraRemoteLink.ps1 b/JiraPS/Public/Get-JiraRemoteLink.ps1 index 875c1b28..769f1c75 100644 --- a/JiraPS/Public/Get-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Get-JiraRemoteLink.ps1 @@ -1,4 +1,5 @@ function Get-JiraRemoteLink { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Get-JiraServerInformation.ps1 b/JiraPS/Public/Get-JiraServerInformation.ps1 index 2f118b51..aee87a3a 100644 --- a/JiraPS/Public/Get-JiraServerInformation.ps1 +++ b/JiraPS/Public/Get-JiraServerInformation.ps1 @@ -1,4 +1,5 @@ function Get-JiraServerInformation { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter()] diff --git a/JiraPS/Public/Get-JiraSession.ps1 b/JiraPS/Public/Get-JiraSession.ps1 index 4e53f9ba..578cd07c 100644 --- a/JiraPS/Public/Get-JiraSession.ps1 +++ b/JiraPS/Public/Get-JiraSession.ps1 @@ -1,4 +1,5 @@ function Get-JiraSession { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param() diff --git a/JiraPS/Public/Get-JiraUser.ps1 b/JiraPS/Public/Get-JiraUser.ps1 index bb88c2ea..807d7587 100644 --- a/JiraPS/Public/Get-JiraUser.ps1 +++ b/JiraPS/Public/Get-JiraUser.ps1 @@ -1,4 +1,5 @@ function Get-JiraUser { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( DefaultParameterSetName = 'Self' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'ByUserName' )] diff --git a/JiraPS/Public/Get-JiraVersion.ps1 b/JiraPS/Public/Get-JiraVersion.ps1 index 22e158c1..116f96b3 100644 --- a/JiraPS/Public/Get-JiraVersion.ps1 +++ b/JiraPS/Public/Get-JiraVersion.ps1 @@ -1,4 +1,5 @@ function Get-JiraVersion { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsPaging, DefaultParameterSetName = 'byId' )] param( [Parameter( Mandatory, ParameterSetName = 'byId' )] diff --git a/JiraPS/Public/Invoke-JiraIssueTransition.ps1 b/JiraPS/Public/Invoke-JiraIssueTransition.ps1 index 3b7db630..e9f96d70 100644 --- a/JiraPS/Public/Invoke-JiraIssueTransition.ps1 +++ b/JiraPS/Public/Invoke-JiraIssueTransition.ps1 @@ -1,4 +1,5 @@ function Invoke-JiraIssueTransition { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/New-JiraFilter.ps1 b/JiraPS/Public/New-JiraFilter.ps1 index 864039ff..5a66a671 100644 --- a/JiraPS/Public/New-JiraFilter.ps1 +++ b/JiraPS/Public/New-JiraFilter.ps1 @@ -1,4 +1,5 @@ function New-JiraFilter { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/New-JiraGroup.ps1 b/JiraPS/Public/New-JiraGroup.ps1 index 9d992074..956709b8 100644 --- a/JiraPS/Public/New-JiraGroup.ps1 +++ b/JiraPS/Public/New-JiraGroup.ps1 @@ -1,4 +1,5 @@ function New-JiraGroup { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/New-JiraIssue.ps1 b/JiraPS/Public/New-JiraIssue.ps1 index ab8917f1..717b6e07 100644 --- a/JiraPS/Public/New-JiraIssue.ps1 +++ b/JiraPS/Public/New-JiraIssue.ps1 @@ -1,4 +1,5 @@ function New-JiraIssue { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/New-JiraSession.ps1 b/JiraPS/Public/New-JiraSession.ps1 index 660722ab..899074e5 100644 --- a/JiraPS/Public/New-JiraSession.ps1 +++ b/JiraPS/Public/New-JiraSession.ps1 @@ -1,4 +1,5 @@ function New-JiraSession { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( diff --git a/JiraPS/Public/New-JiraUser.ps1 b/JiraPS/Public/New-JiraUser.ps1 index 8d1e1c1d..45b8423f 100644 --- a/JiraPS/Public/New-JiraUser.ps1 +++ b/JiraPS/Public/New-JiraUser.ps1 @@ -1,4 +1,5 @@ function New-JiraUser { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/New-JiraVersion.ps1 b/JiraPS/Public/New-JiraVersion.ps1 index 7d6b19c2..287c6125 100644 --- a/JiraPS/Public/New-JiraVersion.ps1 +++ b/JiraPS/Public/New-JiraVersion.ps1 @@ -1,4 +1,5 @@ function New-JiraVersion { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'byObject' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'byObject' )] diff --git a/JiraPS/Public/Remove-JiraFilter.ps1 b/JiraPS/Public/Remove-JiraFilter.ps1 index 886a7709..39bff272 100644 --- a/JiraPS/Public/Remove-JiraFilter.ps1 +++ b/JiraPS/Public/Remove-JiraFilter.ps1 @@ -1,4 +1,5 @@ function Remove-JiraFilter { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( ConfirmImpact = "Medium", SupportsShouldProcess, DefaultParameterSetName = 'ByInputObject' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByInputObject' )] diff --git a/JiraPS/Public/Remove-JiraFilterPermission.ps1 b/JiraPS/Public/Remove-JiraFilterPermission.ps1 index be5affac..d07d5573 100644 --- a/JiraPS/Public/Remove-JiraFilterPermission.ps1 +++ b/JiraPS/Public/Remove-JiraFilterPermission.ps1 @@ -1,4 +1,5 @@ function Remove-JiraFilterPermission { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ByFilterId' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'ByFilterObject' )] diff --git a/JiraPS/Public/Remove-JiraGroup.ps1 b/JiraPS/Public/Remove-JiraGroup.ps1 index d4744652..63aa2616 100644 --- a/JiraPS/Public/Remove-JiraGroup.ps1 +++ b/JiraPS/Public/Remove-JiraGroup.ps1 @@ -1,4 +1,5 @@ function Remove-JiraGroup { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, ConfirmImpact = 'High' )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Remove-JiraGroupMember.ps1 b/JiraPS/Public/Remove-JiraGroupMember.ps1 index 9a6c22fa..f82133fe 100644 --- a/JiraPS/Public/Remove-JiraGroupMember.ps1 +++ b/JiraPS/Public/Remove-JiraGroupMember.ps1 @@ -1,4 +1,5 @@ function Remove-JiraGroupMember { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, ConfirmImpact = 'High' )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Remove-JiraIssue.ps1 b/JiraPS/Public/Remove-JiraIssue.ps1 index d9bc1ee4..075823f9 100644 --- a/JiraPS/Public/Remove-JiraIssue.ps1 +++ b/JiraPS/Public/Remove-JiraIssue.ps1 @@ -1,4 +1,5 @@ function Remove-JiraIssue { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( ConfirmImpact = 'High', SupportsShouldProcess, diff --git a/JiraPS/Public/Remove-JiraIssueAttachment.ps1 b/JiraPS/Public/Remove-JiraIssueAttachment.ps1 index 3586f94b..b3a270c1 100644 --- a/JiraPS/Public/Remove-JiraIssueAttachment.ps1 +++ b/JiraPS/Public/Remove-JiraIssueAttachment.ps1 @@ -1,4 +1,5 @@ function Remove-JiraIssueAttachment { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( ConfirmImpact = 'High', SupportsShouldProcess, DefaultParameterSetName = 'byId' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'byId' )] diff --git a/JiraPS/Public/Remove-JiraIssueLink.ps1 b/JiraPS/Public/Remove-JiraIssueLink.ps1 index 17921300..33c9e133 100644 --- a/JiraPS/Public/Remove-JiraIssueLink.ps1 +++ b/JiraPS/Public/Remove-JiraIssueLink.ps1 @@ -1,4 +1,5 @@ function Remove-JiraIssueLink { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, ConfirmImpact = 'Medium' )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Remove-JiraIssueWatcher.ps1 b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 index 18ea4798..1d8ff434 100644 --- a/JiraPS/Public/Remove-JiraIssueWatcher.ps1 +++ b/JiraPS/Public/Remove-JiraIssueWatcher.ps1 @@ -1,4 +1,5 @@ function Remove-JiraIssueWatcher { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory )] diff --git a/JiraPS/Public/Remove-JiraRemoteLink.ps1 b/JiraPS/Public/Remove-JiraRemoteLink.ps1 index 59de01a8..710b14db 100644 --- a/JiraPS/Public/Remove-JiraRemoteLink.ps1 +++ b/JiraPS/Public/Remove-JiraRemoteLink.ps1 @@ -1,4 +1,5 @@ function Remove-JiraRemoteLink { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( ConfirmImpact = 'High', SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Remove-JiraSession.ps1 b/JiraPS/Public/Remove-JiraSession.ps1 index 08cd039e..1f19c3dc 100644 --- a/JiraPS/Public/Remove-JiraSession.ps1 +++ b/JiraPS/Public/Remove-JiraSession.ps1 @@ -1,4 +1,5 @@ function Remove-JiraSession { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( diff --git a/JiraPS/Public/Remove-JiraUser.ps1 b/JiraPS/Public/Remove-JiraUser.ps1 index 121c956f..3dc6cf21 100644 --- a/JiraPS/Public/Remove-JiraUser.ps1 +++ b/JiraPS/Public/Remove-JiraUser.ps1 @@ -1,4 +1,5 @@ function Remove-JiraUser { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( ConfirmImpact = 'High', SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Remove-JiraVersion.ps1 b/JiraPS/Public/Remove-JiraVersion.ps1 index fac3aaf8..8974c16b 100644 --- a/JiraPS/Public/Remove-JiraVersion.ps1 +++ b/JiraPS/Public/Remove-JiraVersion.ps1 @@ -1,4 +1,5 @@ function Remove-JiraVersion { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( ConfirmImpact = 'High', SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Set-JiraConfigServer.ps1 b/JiraPS/Public/Set-JiraConfigServer.ps1 index a95d7ebb..00c85b5e 100644 --- a/JiraPS/Public/Set-JiraConfigServer.ps1 +++ b/JiraPS/Public/Set-JiraConfigServer.ps1 @@ -1,4 +1,5 @@ function Set-JiraConfigServer { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] param( diff --git a/JiraPS/Public/Set-JiraFilter.ps1 b/JiraPS/Public/Set-JiraFilter.ps1 index 68902f3a..ac22ba86 100644 --- a/JiraPS/Public/Set-JiraFilter.ps1 +++ b/JiraPS/Public/Set-JiraFilter.ps1 @@ -1,4 +1,5 @@ function Set-JiraFilter { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline )] diff --git a/JiraPS/Public/Set-JiraIssue.ps1 b/JiraPS/Public/Set-JiraIssue.ps1 index 337c0132..7f219d0d 100644 --- a/JiraPS/Public/Set-JiraIssue.ps1 +++ b/JiraPS/Public/Set-JiraIssue.ps1 @@ -1,4 +1,5 @@ function Set-JiraIssue { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Set-JiraIssueLabel.ps1 b/JiraPS/Public/Set-JiraIssueLabel.ps1 index 8fde41fa..4139f5c6 100644 --- a/JiraPS/Public/Set-JiraIssueLabel.ps1 +++ b/JiraPS/Public/Set-JiraIssueLabel.ps1 @@ -1,4 +1,5 @@ function Set-JiraIssueLabel { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ReplaceLabels' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Set-JiraUser.ps1 b/JiraPS/Public/Set-JiraUser.ps1 index 93ef46ff..b89b7eb0 100644 --- a/JiraPS/Public/Set-JiraUser.ps1 +++ b/JiraPS/Public/Set-JiraUser.ps1 @@ -1,4 +1,5 @@ function Set-JiraUser { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess, DefaultParameterSetName = 'ByNamedParameters' )] param( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] diff --git a/JiraPS/Public/Set-JiraVersion.ps1 b/JiraPS/Public/Set-JiraVersion.ps1 index 3a96f82d..18c104ce 100644 --- a/JiraPS/Public/Set-JiraVersion.ps1 +++ b/JiraPS/Public/Set-JiraVersion.ps1 @@ -1,4 +1,5 @@ function Set-JiraVersion { + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsShouldProcess )] param( [Parameter( Mandatory, ValueFromPipeline )] From ccdbb3ec38e19abb87ecfb249372379440ddcb1e Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 25 Jun 2018 18:24:51 +0200 Subject: [PATCH 77/83] Fixed tests for PSv3 --- Tests/New-JiraSession.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/New-JiraSession.Tests.ps1 b/Tests/New-JiraSession.Tests.ps1 index ef6f9f4d..3166f732 100644 --- a/Tests/New-JiraSession.Tests.ps1 +++ b/Tests/New-JiraSession.Tests.ps1 @@ -29,7 +29,7 @@ Describe "New-JiraSession" { Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {$Method -eq 'Get' -and $Uri -like "*/rest/api/*/mypermissions"} { ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri' - [Microsoft.PowerShell.Commands.WebRequestSession]::new() + New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession } Mock Invoke-JiraMethod -ModuleName JiraPS { From 9a7872d8cf955088a72aaf19a2e277377c63b0aa Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 25 Jun 2018 18:30:49 +0200 Subject: [PATCH 78/83] Removed excessive debug messages --- JiraPS/Public/Invoke-JiraMethod.ps1 | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index 3c935925..b721029d 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -1,5 +1,6 @@ function Invoke-JiraMethod { - #Requires -Version 3 + #requires -Version 3 + # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsPaging )] param ( @@ -48,7 +49,7 @@ function Invoke-JiraMethod { [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty, - [Parameter( DontShow )] + # [Parameter( DontShow )] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $Cmdlet = $PSCmdlet @@ -154,7 +155,6 @@ function Invoke-JiraMethod { #region Execute the actual query try { - Write-Debug ($splatParameters | Out-String) Write-Verbose "[$($MyInvocation.MyCommand.Name)] $($splatParameters.Method) $($splatParameters.Uri)" Write-Debug "[$($MyInvocation.MyCommand.Name)] Invoke-WebRequest with `$splatParameters: $($splatParameters | Out-String)" # Invoke the API @@ -195,8 +195,6 @@ function Invoke-JiraMethod { if ($webResponse.Content) { $response = ConvertFrom-Json ([Text.Encoding]::UTF8.GetString($webResponse.RawContentStream.ToArray())) - Write-Debug ($response | Out-String) - if ($Paging) { # Remove Parameters that don't need propagation $script:PSDefaultParameterValues.Remove("$($MyInvocation.MyCommand.Name):IncludeTotalCount") @@ -212,14 +210,13 @@ function Invoke-JiraMethod { foreach ($container in $script:PagingContainers) { if (($response) -and ($response | Get-Member -Name $container)) { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Extracting data from [$container] containter" $result = $response.$container } } $total += @($result).Count - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] New total: $total" $pageSize = $response.maxResults - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] New pageSize: $pageSize" if ($total -gt $PSCmdlet.PagingParameters.First) { Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Only output the first $($PSCmdlet.PagingParameters.First % $pageSize) of page" @@ -229,33 +226,28 @@ function Invoke-JiraMethod { $converter = "ConvertTo-$($OutputType)" if (Test-Path function:\$converter) { # Results shall be casted to custom objects (see ValidateSet) - Write-Verbose "[$($MyInvocation.MyCommand.Name)] Outputting results as $($OutputType)" + Write-Debug "[$($MyInvocation.MyCommand.Name)] Outputting `$result as $($OutputType)" Write-Output ($result | & $converter) } else { + Write-Debug "[$($MyInvocation.MyCommand.Name)] Outputting `$result" Write-Output ($result) } if ($total -ge $PSCmdlet.PagingParameters.First) { - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] breaking as $total is more than $($PSCmdlet.PagingParameters.First)" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Stopping paging, as $total reached $($PSCmdlet.PagingParameters.First)" break } # calculate the size of the next page - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] next page begins at $total" $PSBoundParameters["GetParameter"]["startAt"] = $total + $offset - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] doesn't it? $($PSBoundParameters["GetParameter"]["startAt"])" $expectedTotal = $PSBoundParameters["GetParameter"]["startAt"] + $pageSize - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] expecting to have $expectedTotal entries in total with next page" if ($expectedTotal -gt $PSCmdlet.PagingParameters.First) { $reduceBy = $expectedTotal - $PSCmdlet.PagingParameters.First - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] reducing next pagesize by $reduceBy" $PSBoundParameters["GetParameter"]["maxResults"] = $pageSize - $reduceBy } # Inquire the next page - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] about to invoke with : $($PSBoundParameters | Out-String)" - Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] about to invoke with : $($PSBoundParameters["GetParameter"] | Out-String)" $response = Invoke-JiraMethod @PSBoundParameters # Expand data container of paged results From c9cfd4384f80244e37e09227e8ad3e32cea87e3d Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 25 Jun 2018 18:31:17 +0200 Subject: [PATCH 79/83] Added verbose messages and error for when body is empty --- JiraPS/Private/Resolve-ErrorWebResponse.ps1 | 31 ++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/JiraPS/Private/Resolve-ErrorWebResponse.ps1 b/JiraPS/Private/Resolve-ErrorWebResponse.ps1 index 4528350c..853a30b1 100644 --- a/JiraPS/Private/Resolve-ErrorWebResponse.ps1 +++ b/JiraPS/Private/Resolve-ErrorWebResponse.ps1 @@ -11,6 +11,8 @@ function Resolve-ErrorWebResponse { ) begin { + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started" + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)" Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)" @@ -20,26 +22,27 @@ function Resolve-ErrorWebResponse { } # Powershell v5.1- has the body of the response in a Stream in the Exception Response else { - Write-Verbose 1 $readStream = New-Object -TypeName System.IO.StreamReader -ArgumentList ($Exception.Exception.Response.GetResponseStream()) $responseBody = $readStream.ReadToEnd() $readStream.Close() } + $exception = "Invalid Server Response" + $errorId = "InvalidResponse.Status$($StatusCode.value__)" + $errorCategory = "InvalidResult" + if ($responseBody) { # Clear the body in case it is not a JSON (but rather html) - if ($responseBody -match "^[\s\t]*\") { $responseBody = '{"errorMessages": "Invalid server response. HTML returned."}' } + if ($responseBody -match "^[\s\t]*\") { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Content is HTML - replacing it with a generic json" + $responseBody = '{"errorMessages": "Invalid server response. HTML returned."}' + } Write-Verbose "[$($MyInvocation.MyCommand.Name)] Retrieved body of HTTP response for more information about the error (`$responseBody)" Write-Debug "[$($MyInvocation.MyCommand.Name)] Got the following error as `$responseBody" - $exception = "Invalid Server Response" - $errorId = "InvalidResponse.Status$($StatusCode.value__)" - $errorCategory = "InvalidResult" - try { $responseObject = ConvertFrom-Json -InputObject $responseBody -ErrorAction Stop - Write-Debug "aaaa `$responseObject" foreach ($_error in ($responseObject.errorMessages + $responseObject.errors)) { # $_error is a PSCustomObject - therefore can't be $false @@ -57,6 +60,7 @@ function Resolve-ErrorWebResponse { } } catch [ArgumentException] { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] `$responseBody could not be converted from JSON" $writeErrorSplat = @{ Exception = $exception ErrorId = $errorId @@ -79,5 +83,18 @@ function Resolve-ErrorWebResponse { WriteError @writeErrorSplat } } + else { + Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] Response had no Body. Using `$StatusCode for generic error" + $writeErrorSplat = @{ + Exception = $exception + ErrorId = $errorId + Category = $errorCategory + Message = "Server responsed with $StatusCode" + Cmdlet = $Cmdlet + } + WriteError @writeErrorSplat + } + + Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended" } } From 77f48b119bc520427635d8a41e83c28b77600840 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Mon, 25 Jun 2018 20:04:18 +0200 Subject: [PATCH 80/83] Removed script requires tag --- JiraPS/Public/Invoke-JiraMethod.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/JiraPS/Public/Invoke-JiraMethod.ps1 b/JiraPS/Public/Invoke-JiraMethod.ps1 index b721029d..61448d6e 100644 --- a/JiraPS/Public/Invoke-JiraMethod.ps1 +++ b/JiraPS/Public/Invoke-JiraMethod.ps1 @@ -1,5 +1,4 @@ function Invoke-JiraMethod { - #requires -Version 3 # .ExternalHelp ..\JiraPS-help.xml [CmdletBinding( SupportsPaging )] param From cef287c7b51c6ce60de72fa7c79ce3d77e846073 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 26 Jun 2018 21:05:30 +0200 Subject: [PATCH 81/83] Added tests to ensure a function links to the external help this is required for powershell v3 --- Tests/JiraPS.Help.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/JiraPS.Help.Tests.ps1 b/Tests/JiraPS.Help.Tests.ps1 index 08cc814e..449b9d3c 100644 --- a/Tests/JiraPS.Help.Tests.ps1 +++ b/Tests/JiraPS.Help.Tests.ps1 @@ -67,6 +67,12 @@ Describe "Help tests" -Tag Documentation { Test-Path $markdownFile | Should -Be $true } + It "links the function to the external help" { + # required for PowerShell v3 + $Pattern = [regex]::Escape("# .ExternalHelp ..\JiraPS-help.xml") + $command.Definition -match $Pattern + } + It "does not have Comment-Based Help" { # We use .EXAMPLE, as we test this extensivly and it is never auto-generated $command.Definition | Should -Not -BeNullOrEmpty From 905809d0c82b948e5b7c93852ef051977cbd0751 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 27 Jun 2018 10:25:38 +0200 Subject: [PATCH 82/83] Added missing warning for deprecated parameters --- JiraPS/Public/Get-JiraIssue.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/JiraPS/Public/Get-JiraIssue.ps1 b/JiraPS/Public/Get-JiraIssue.ps1 index 92279054..517b83fb 100644 --- a/JiraPS/Public/Get-JiraIssue.ps1 +++ b/JiraPS/Public/Get-JiraIssue.ps1 @@ -145,9 +145,11 @@ function Get-JiraIssue { } # 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 } @@ -180,9 +182,11 @@ function Get-JiraIssue { } # 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 } From dd689c73de5cc92de2d1a8f1c266b7746c2e36b5 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 27 Jun 2018 10:26:11 +0200 Subject: [PATCH 83/83] Release of v2.8 --- CHANGELOG.md | 25 +++++++ JiraPS/JiraPS.psd1 | 2 +- _posts/2018-06-28-JiraPS-v2.8.md | 111 +++++++++++++++++++++++++++++++ appveyor.yml | 2 +- 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 _posts/2018-06-28-JiraPS-v2.8.md diff --git a/CHANGELOG.md b/CHANGELOG.md index d3487cd1..2c494f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Change Log +## 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). + +### IMPROVEMENTS + +- Added support for paginated response from API server by means of `-Paging` (#291, [@lipkau[]]) +- Added full set of functions to manage Filter Permissions (#289, [@lipkau[]]) +- Added `-Id` parameter to `Remove-JiraFilter` (#288, [@lipkau[]]) +- Changed logic of `Get-JiraUser` to return multiple results for a search (#272, [@lipkau[]]) +- Added posts for homepage to the module's repository (#268, [@lipkau[]]) +- Improved handling of _Credentials_ (#271, [@lipkau[]]) +- Added missing interactions with _Filters_ (#266, [@lipkau[]]) +- Added `Remove-JiraIssue` (#265, [@hmmwhatsthisdo[]]) +- Improved Build script (to deploy changes to the homepage) (#259, [@lipkau[]]) + +### BUG FIXES + +- Reverted `Add-JiraIssueAttachament` as JiraPS v2.7 broke it (#287, [@lipkau[]]) +- Fixed resolving of Remote Link (#286, [@lipkau[]]) +- Improved error handling for ErrorDetails and non-JSON/HTML responses (#277, [@hmmwhatsthisdo[]]) +- Fully support Powershell v3 (#273, [@lipkau[]]) +- Fixed parameter used in documentation but not in code (#263, [@lipkau[]]) + ## 2.7 - 2018-05-13 More detailed description about the changes can be found on [Our Website](https://atlassianps.org/article/announcement/JiraPS-v2.7.html). @@ -258,6 +282,7 @@ which is in turn inspired by the [Vagrant](https://github.com/mitchellh/vagrant/ [@colhal]: https://github.com/colhal [@Dejulia489]: https://github.com/Dejulia489 [@ebekker]: https://github.com/ebekker + [@hmmwhatsthisdo]: https://github.com/hmmwhatsthisdo [@jkknorr]: https://github.com/jkknorr [@kittholland]: https://github.com/kittholland [@LiamLeane]: https://github.com/LiamLeane diff --git a/JiraPS/JiraPS.psd1 b/JiraPS/JiraPS.psd1 index 9959680a..6dba9ffe 100644 --- a/JiraPS/JiraPS.psd1 +++ b/JiraPS/JiraPS.psd1 @@ -4,7 +4,7 @@ RootModule = 'JiraPS.psm1' # Version number of this module. - ModuleVersion = '2.7' + ModuleVersion = '2.8' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/_posts/2018-06-28-JiraPS-v2.8.md b/_posts/2018-06-28-JiraPS-v2.8.md new file mode 100644 index 00000000..c52df538 --- /dev/null +++ b/_posts/2018-06-28-JiraPS-v2.8.md @@ -0,0 +1,111 @@ +--- +layout: article +permalink: /article/:categories/:title +title: JiraPS v2.8 +date: 2018-06-28 12:00:00 +categories: Announcement +thumbnail: +author: lipkau +tags: + - JiraPS + - Release +--- + +We have just uploaded a new version of the **JiraPS** module to the [Gallery](https://www.powershellgallery.com/packages/JiraPS/2.8.0) and to [GitHub](https://github.com/AtlassianPS/JiraPS/tree/v2.8.0). + + +## Description + +This release brings new functionality, improvements and bug fixes that has been submitted by our contributors. + +## CHANGELOG + +### IMPROVEMENTS + +- Added support for paginated response from API server by means of `-Paging` (#291, [@lipkau[]]) + - moved default values to `JiraPS.psm1` so that they could be changed from outside of the module + _in preparation for using `Configuration`_ + - added logic for `Command parameters` > `Global defaults` > `module defaults` + - huge improvement to Unit Tests for `Invoke-JiraMethod` + - improved how HTTP responses > 399 are handled (`Resolve-ErrorWebResponse`) + - added `.EXTERNALHELP` to all functions (needed for Powershell v3) + - updated all functions which can use paging so that they use the new `-Paging` functionality + - `Get-JiraGroupMember` + - `Get-JiraIssue -Query` + - `Get-JiraIssue -Filter` + - `Get-JiraIssueComment` + - `Get-JiraVersion` + - added `-Sort` to influence the sorting of the results + - added default `PageSize` + - marked parameters which duplicate `[SupportsPaging]` parameter as **deprecated**. These are: + - `Get-JiraGroupMember -StartIndex` + - `Get-JiraGroupMember -MaxResults` + - `Get-JiraIssue -StartIndex` + - `Get-JiraIssue -MaxResults` + - added `-Headers` logic to `New-JiraSession` +- Updated `Pester` to version `4.3.1` (#289, [@lipkau[]]) +- Added full set of functions to manage Filter Permissions (#289, [@lipkau[]]) + - introduced a new Object _`[JiraPS.FilterPermission]`_ + - added property `FilterPermissions` to _`[JiraPS.Filter]`_ which is the list of _`[JiraPS.FilterPermission]`_ + of this Filter + - introduced a new Object _`[JiraPS.ProjectRole]`_ + - added `Add-JiraFilterPermission` + - added `Get-JiraFilterPermission` + - added `Remove-JiraFilterPermission` +- Added `-Id` parameter to `Remove-JiraFilter` (#288, [@lipkau[]]) + - by adding `-Id` parameter (which accepts a value by pipeline), this function can now + be used in scenarios like `Get-Content "listOfFilter.txt | Remover-JiraFilter` +- Changed logic of `Get-JiraUser` to return multiple results for a search (#272, [@lipkau[]]) + - `Get-JiraUser` was hardcoded to return only one result, while the API can return multiple results + - added parameter (`-MaxResults`, `-Skip`) to influence the results of the API + - _API has a limitation of 1000 items in response_ +- Added posts for homepage to the module's repository (#268, [@lipkau[]]) + - by maintaining the posts of the homepage in the module's repository, the new version of the + module can be deployed without manual changes to the homepage (thanks to #259 mentioned bellow) +- Improved handling of _Credentials_ (#271, [@lipkau[]]) + - added an empty _`[Credential]`_ object as default value + - `-Credentail "Username"` now uses the _`[String]`_ as value for the Username in the Credentials dialog + - this change is important for Powershell v3 compatibility +- Added missing interactions with _Filters_ (#266, [@lipkau[]]) + - added `-Favorite` to `Get-JiraFilter`, which lists all Filters marked as favorite by the user + - added `New-JiraFilter` + - added `Remove-JiraFilter` + - added `Set-JiraFilter` +- Added `Remove-JiraIssue` (#265, [@hmmwhatsthisdo[]]) +- Improved Build script (to deploy changes to the homepage) (#259, [@lipkau[]]) + +### BUG FIXES + +- Reverted `Add-JiraIssueAttachament` as JiraPS v2.7 broke it (#287, [@lipkau[]]) + - `JiraPS v2.7` tried to move the logic for generating the `multipart/form-data` to `Invoke-WebRequest` + - this is still desired, but as it broke the functionality of `Add-JiraIssueAttachament`, + this was rolled-back + - shall be fixed/re-implemented with [#284](https://github.com/AtlassianPS/JiraPS/issues/284) +- Fixed resolving of Remote Link (#286, [@lipkau[]]) + - function was using the wrong private function for converting the response to custom object +- Improved error handling for ErrorDetails and non-JSON/HTML responses (#277, [@hmmwhatsthisdo[]]) +- Fully support Powershell v3 (#273, [@lipkau[]]) +- Fixed parameter used in documentation but not in code (#263, [@lipkau[]]) + - added alias `-Issue` to `Get-JiraIssue -Key` as the documentation used it + - updated documentation to use the `-Key` parameter + +_Full list of issues can be found in [Milestone v2.8](https://github.com/AtlassianPS/JiraPS/milestone/11)._ + + + [@alexsuslin]: https://github.com/alexsuslin + [@axxelG]: https://github.com/axxelG + [@beaudryj]: https://github.com/beaudryj + [@brianbunke]: https://github.com/brianbunke + [@Clijsters]: https://github.com/Clijsters + [@colhal]: https://github.com/colhal + [@Dejulia489]: https://github.com/Dejulia489 + [@ebekker]: https://github.com/ebekker + [@hmmwhatsthisdo]: https://github.com/hmmwhatsthisdo + [@jkknorr]: https://github.com/jkknorr + [@kittholland]: https://github.com/kittholland + [@LiamLeane]: https://github.com/LiamLeane + [@lipkau]: https://github.com/lipkau + [@lukhase]: https://github.com/lukhase + [@padgers]: https://github.com/padgers + [@ThePSAdmin]: https://github.com/ThePSAdmin + [@WindowsAdmin92]: https://github.com/WindowsAdmin92 diff --git a/appveyor.yml b/appveyor.yml index da589401..46d23e84 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,7 +16,7 @@ environment: matrix: fast_finish: true -version: 2.7.{build} +version: 2.8.{build} # Don't rebuild when I tag a release on GitHub skip_tags: true