From 13f28c181b0723de0afb1bdf406de56e4b1ede19 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 8 Nov 2016 13:26:32 +0100 Subject: [PATCH 1/8] added Get-JiraIssueEditMetadata --- .../Internal/ConvertTo-JiraEditMeraField.ps1 | 99 +++++++++++++++++++ PSJira/Public/Get-JiraIssueEditMetadata.ps1 | 96 ++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 PSJira/Internal/ConvertTo-JiraEditMeraField.ps1 create mode 100644 PSJira/Public/Get-JiraIssueEditMetadata.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraEditMeraField.ps1 b/PSJira/Internal/ConvertTo-JiraEditMeraField.ps1 new file mode 100644 index 00000000..958a2ef0 --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraEditMeraField.ps1 @@ -0,0 +1,99 @@ +function ConvertTo-JiraEditMetaField +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, + Position = 0, + ValueFromPipeline = $true)] + [PSObject[]] $InputObject, + + [Switch] $ReturnError + ) + + process + { + foreach ($i in $InputObject) + { + Write-Debug "[ConvertTo-JiraEditMetaField] Processing object: '$i'" + + if ($i.errorMessages) + { +# Write-Debug "[ConvertTo-JiraEditMetaField] Detected an errorMessages property. This is an error result." + + if ($ReturnError) + { +# Write-Debug "[ConvertTo-JiraEditMetaField] Outputting details about error message" + $props = @{ + 'ErrorMessages' = $i.errorMessages; + } + + $result = New-Object -TypeName PSObject -Property $props + $result.PSObject.TypeNames.Insert(0, 'PSJira.Error') + + Write-Output $result + } + } else { + $fields = $i.fields + $fieldNames = (Get-Member -InputObject $fields -MemberType '*Property').Name + foreach ($f in $fieldNames) + { + Write-Debug "[ConvertTo-JiraEditMetaField] Processing field [$f]" + $item = $fields.$f + + $props = @{ + 'Id' = $f; + 'Name' = $item.name; + 'HasDefaultValue' = [System.Convert]::ToBoolean($item.hasDefaultValue); + 'Required' = [System.Convert]::ToBoolean($item.required); + 'Schema' = $item.schema; + 'Operations' = $item.operations; + } + + if ($item.allowedValues) + { +# Write-Debug "[ConvertTo-JiraEditMetaField] Adding AllowedValues" + $props.AllowedValues = $item.allowedValues + } + + if ($item.autoCompleteUrl) + { +# Write-Debug "[ConvertTo-JiraEditMetaField] Adding AutoCompleteURL" + $props.AutoCompleteUrl = $item.autoCompleteUrl + } + +# Write-Debug "[ConvertTo-JiraEditMetaField] Checking for any additional properties" + foreach ($extraProperty in (Get-Member -InputObject $item -MemberType NoteProperty).Name) + { +# Write-Debug "[ConvertTo-JiraEditMetaField] Checking property $extraProperty" + if ($props.$extraProperty -eq $null) + { +# Write-Debug "[ConvertTo-JiraEditMetaField] - Adding property [$extraProperty]" + $props.$extraProperty = $item.$extraProperty + } + } + +# Write-Debug "[ConvertTo-JiraEditMetaField] Creating PSObject out of properties" + $result = New-Object -TypeName PSObject -Property $props + +# Write-Debug "[ConvertTo-JiraEditMetaField] Inserting type name information" + $result.PSObject.TypeNames.Insert(0, 'PSJira.EditMetaField') + +# Write-Debug "[ConvertTo-JiraEditMetaField] Inserting custom toString() method" + $result | Add-Member -MemberType ScriptMethod -Name "ToString" -Force -Value { + Write-Output "$($this.Name)" + } + +# Write-Debug "[ConvertTo-JiraEditMetaField] Outputting object" + Write-Output $result + } + } + } + } + + end + { +# Write-Debug "[ConvertTo-JiraEditMetaField] Complete" + } +} + + diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 new file mode 100644 index 00000000..74d5d53b --- /dev/null +++ b/PSJira/Public/Get-JiraIssueEditMetadata.ps1 @@ -0,0 +1,96 @@ +function Get-JiraIssueEditMetadata +{ + <# + .Synopsis + Returns metadata required to create an issue in JIRA + .DESCRIPTION + This function returns metadata required to create an issue in JIRA - the fields that can be defined in the process of creating an issue. This can be used to identify custom fields in order to pass them to New-JiraIssue. + + This function is particularly useful when your JIRA instance includes custom fields that are marked as mandatory. The required fields can be identified from this See the examples for more details on this approach. + .EXAMPLE + Get-JiraIssueEditMetadata -Project 'TEST' -IssueType 'Bug' + This example returns the fields available when creating an issue of type Bug under project TEST. + .EXAMPLE + Get-JiraIssueEditMetadata -Project 'JIRA' -IssueType 'Bug' | ? {$_.Required -eq $true} + This example returns fields available when creating an issue of type Bug under the project Jira. It then uses Where-Object (aliased by the question mark) to filter only the fields that are required. + .INPUTS + This function does not accept pipeline input. + .OUTPUTS + This function outputs the PSJira.Field objects that represent JIRA's create metadata. + .NOTES + This function requires either the -Credential parameter to be passed or a persistent JIRA session. See New-JiraSession for more details. If neither are supplied, this function will run with anonymous access to JIRA. + #> + [CmdletBinding()] + param( + # Issue id or key + [Parameter(Mandatory = $true, + Position = 0)] + [String] $Issue, + + [String] $ConfigFile, + + # Credentials to use to connect to Jira + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] $Credential + ) + + begin + { + Write-Debug "[Get-JiraIssueEditMetadata] Reading server from config file" + try + { + $server = Get-JiraConfigServer -ConfigFile $ConfigFile -ErrorAction Stop + } catch { + $err = $_ + Write-Debug "[Get-JiraIssueEditMetadata] Encountered an error reading the Jira server." + throw $err + } + + Write-Debug "[Get-JiraIssueEditMetadata] Building URI for REST call based on parameters" + $uri = "$server/rest/api/latest/issue/$Issue/editmeta" + } + + process + { + Write-Debug "[Get-JiraIssueEditMetadata] Preparing for blastoff!" + $jiraResult = Invoke-JiraMethod -Method Get -URI $uri -Credential $Credential + + if ($jiraResult) + { + if (@($jiraResult.projects).Count -eq 0) + { + Write-Debug "[Get-JiraIssueEditMetadata] No project results were found. Throwing exception." + throw "No projects were found for the given project [$Project]. Use Get-JiraProject for more details." + } elseif (@($jiraResult.projects).Count -gt 1) { + Write-Debug "[Get-JiraIssueEditMetadata] Multiple project results were found. Throwing exception." + throw "Multiple projects were found for the given project [$Project]. Refine the parameters to return only one project." + } + + $projectId = $jiraResult.projects.id + $projectKey = $jiraResult.projects.key + + Write-Debug "[Get-JiraIssueEditMetadata] Identified project key: [$Project]" + + if (@($jiraResult.projects.issuetypes) -eq 0) + { + Write-Debug "[Get-JiraIssueEditMetadata] No issue type results were found. Throwing exception." + throw "No issue types were found for the given issue type [$IssueType]. Use Get-JiraIssueType for more details." + } elseif (@($jiraResult.projects.issuetypes).Count -gt 1) { + Write-Debug "[Get-JiraIssueEditMetadata] Multiple issue type results were found. Throwing exception." + throw "Multiple issue types were found for the given issue type [$IssueType]. Refine the parameters to return only one issue type." + } + + Write-Debug "[Get-JiraIssueEditMetadata] Converting results to custom object" + $obj = ConvertTo-JiraEditMetaField -InputObject $jiraResult + + Write-Debug "Outputting results" + Write-Output $obj + +# Write-Output $jiraResult + } else { + Write-Debug "[Get-JiraIssueEditMetadata] No results were returned from JIRA." + } + } +} + + From 8866c90309c5c2bb0ee2cd3ff45d932ee10e2782 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 8 Nov 2016 13:26:45 +0100 Subject: [PATCH 2/8] updated manifest to export function --- PSJira/PSJira.psd1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/PSJira/PSJira.psd1 b/PSJira/PSJira.psd1 index fa968ad6..1777ba8f 100644 --- a/PSJira/PSJira.psd1 +++ b/PSJira/PSJira.psd1 @@ -69,15 +69,15 @@ FormatsToProcess = 'PSJira.format.ps1xml' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira', - 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', - 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', - 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', - 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', - 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', - 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', - 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', - 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', +FunctionsToExport = 'Add-JiraGroupMember', 'Add-JiraIssueComment', 'Format-Jira', + 'Get-JiraConfigServer', 'Get-JiraField', 'Get-JiraFilter', + 'Get-JiraGroup', 'Get-JiraGroupMember', 'Get-JiraIssue', + 'Get-JiraIssueComment', 'Get-JiraIssueCreateMetadata', 'Get-JiraIssueEditMetadata', + 'Get-JiraIssueType', 'Get-JiraPriority', 'Get-JiraProject', + 'Get-JiraSession', 'Get-JiraUser', 'Invoke-JiraIssueTransition', + 'New-JiraGroup', 'New-JiraIssue', 'New-JiraSession', 'New-JiraUser', + 'Remove-JiraGroup', 'Remove-JiraGroupMember', 'Remove-JiraSession', + 'Remove-JiraUser', 'Set-JiraConfigServer', 'Set-JiraIssue', 'Set-JiraIssueLabel', 'Set-JiraUser' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. @@ -122,7 +122,7 @@ PrivateData = @{ # ExternalModuleDependencies = '' } # End of PSData hashtable - + } # End of PrivateData hashtable # HelpInfo URI of this module From f01aed72e3669374072d66b7e13743f0bfe9aa67 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Tue, 8 Nov 2016 13:26:59 +0100 Subject: [PATCH 3/8] added Unit Tests --- .../ConvertTo-JiraEditMetaField.Tests.ps1 | 113 ++++++++ .../Public/Get-JiraIssueEditMetadata.Test.ps1 | 252 ++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100644 PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 create mode 100644 PSJira/Public/Get-JiraIssueEditMetadata.Test.ps1 diff --git a/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 new file mode 100644 index 00000000..b225717c --- /dev/null +++ b/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 @@ -0,0 +1,113 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +Describe "ConvertTo-JiraEditMetaField" { + function defProp($obj, $propName, $propValue) + { + It "Defines the '$propName' property" { + $obj.$propName | Should Be $propValue + } + } + + $sampleJson = @' +{ + "fields": { + "summary": { + "required": true, + "schema": { + "type": "string", + "system": "summary" + }, + "name": "Summary", + "hasDefaultValue": false, + "operations": [ + "set" + ] + }, + "priority": { + "required": false, + "schema": { + "type": "priority", + "system": "priority" + }, + "name": "Priority", + "hasDefaultValue": true, + "operations": [ + "set" + ], + "allowedValues": [ + { + "self": "http://jiraserver.example.com/rest/api/2/priority/1", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/blocker.png", + "name": "Block", + "id": "1" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/2", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/critical.png", + "name": "Critical", + "id": "2" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/3", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/major.png", + "name": "Major", + "id": "3" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/4", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/minor.png", + "name": "Minor", + "id": "4" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/5", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/trivial.png", + "name": "Trivial", + "id": "5" + } + ] + } + } + } +} +'@ + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson + + $r = ConvertTo-JiraEditMetaField $sampleObject + + It "Creates PSObjects out of JSON input" { + $r | Should Not BeNullOrEmpty + $r.Count | Should Be 2 + } + + It "Sets the type name to PSJira.CreateMetaField" { + # Need to use the pipeline in this case, instead of directly using the + # -InputObject parameter. This is a quirk of PowerShell, arrays, and + # the pipeline. + ($r | Get-Member).TypeName | Should Be 'PSJira.EditMetaField' + } + + Context "Data validation" { + # Our sample JSON includes two fields: summary and priority. + $summary = ConvertTo-JiraEditMetaField $sampleObject | Where-Object -FilterScript {$_.Name -eq 'Summary'} + $priority = ConvertTo-JiraEditMetaField $sampleObject | Where-Object -FilterScript {$_.Name -eq 'Priority'} + + defProp $summary 'Id' 'summary' + defProp $summary 'Name' 'Summary' + defProp $summary 'HasDefaultValue' $false + defProp $summary 'Required' $true + defProp $summary 'Operations' @('set') + + It "Defines the 'Schema' property if available" { + $summary.Schema | Should Not BeNullOrEmpty + $priority.Schema | Should Not BeNullOrEmpty + } + + It "Defines the 'AllowedValues' property if available" { + $summary.AllowedValues | Should BeNullOrEmpty + $priority.AllowedValues | Should Not BeNullOrEmpty + } + } +} diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.Test.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.Test.ps1 new file mode 100644 index 00000000..4b3fe270 --- /dev/null +++ b/PSJira/Public/Get-JiraIssueEditMetadata.Test.ps1 @@ -0,0 +1,252 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") +. "$here\$sut" + +InModuleScope PSJira { + + $ShowMockData = $false + $ShowDebugText = $false + + Describe "Get-JiraIssueEditMetadata" { + + if ($ShowDebugText) + { + Mock 'Write-Debug' { + Write-Host " [DEBUG] $Message" -ForegroundColor Yellow + } + } + + $issueID = 41701 + $issueKey = 'IT-3676' + + Mock Get-JiraConfigServer { + '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 -ModuleName PSJira { + if ($ShowMockData) + { + Write-Host " Mocked Invoke-WebRequest" -ForegroundColor Cyan + Write-Host " [Uri] $Uri" -ForegroundColor Cyan + Write-Host " [Method] $Method" -ForegroundColor Cyan + } + } + + Context "Sanity checking" { + $command = Get-Command -Name Get-JiraIssueEditMetadata + + function defParam($name) + { + It "Has a -$name parameter" { + $command.Parameters.Item($name) | Should Not BeNullOrEmpty + } + } + + defParam 'Issue' + defParam 'Credential' + } + + Context "Behavior testing" { + + $restResult = ConvertFrom-Json2 @' +{ + "fields": { + "summary": { + "required": true, + "schema": { + "type": "string", + "system": "summary" + }, + "name": "Summary", + "hasDefaultValue": false, + "operations": [ + "set" + ] + }, + "issuetype": { + "required": true, + "schema": { + "type": "issuetype", + "system": "issuetype" + }, + "name": "Issue Type", + "hasDefaultValue": false, + "operations": [], + "allowedValues": [ + { + "self": "https://jira.example.com/rest/api/2/issuetype/2", + "id": "2", + "description": "This is a test issue type", + "iconUrl": "https://jira.example.com/images/icons/issuetypes/newfeature.png", + "name": "Test Issue Type", + "subtask": false + } + ] + }, + "description": { + "required": false, + "schema": { + "type": "string", + "system": "description" + }, + "name": "Description", + "hasDefaultValue": false, + "operations": [ + "set" + ] + }, + "project": { + "required": true, + "schema": { + "type": "project", + "system": "project" + }, + "name": "Project", + "hasDefaultValue": false, + "operations": [ + "set" + ], + "allowedValues": [ + { + "self": "https://jira.example.com/rest/api/2/project/10003", + "id": "10003", + "key": "TEST", + "name": "Test Project", + "projectCategory": { + "self": "https://jira.example.com/rest/api/2/projectCategory/10000", + "id": "10000", + "description": "All Project Catagories", + "name": "All Project" + } + } + ] + }, + "reporter": { + "required": true, + "schema": { + "type": "user", + "system": "reporter" + }, + "name": "Reporter", + "autoCompleteUrl": "https://jira.example.com/rest/api/latest/user/search?username=", + "hasDefaultValue": false, + "operations": [ + "set" + ] + }, + "assignee": { + "required": false, + "schema": { + "type": "user", + "system": "assignee" + }, + "name": "Assignee", + "autoCompleteUrl": "https://jira.example.com/rest/api/latest/user/assignable/search?issueKey=null&username=", + "hasDefaultValue": false, + "operations": [ + "set" + ] + }, + "priority": { + "required": false, + "schema": { + "type": "priority", + "system": "priority" + }, + "name": "Priority", + "hasDefaultValue": true, + "operations": [ + "set" + ], + "allowedValues": [ + { + "self": "https://jira.example.com/rest/api/2/priority/1", + "iconUrl": "https://jira.example.com/images/icons/priorities/blocker.png", + "name": "Blocker", + "id": "1" + }, + { + "self": "https://jira.example.com/rest/api/2/priority/2", + "iconUrl": "https://jira.example.com/images/icons/priorities/critical.png", + "name": "Critical", + "id": "2" + }, + { + "self": "https://jira.example.com/rest/api/2/priority/3", + "iconUrl": "https://jira.example.com/images/icons/priorities/major.png", + "name": "Major", + "id": "3" + }, + { + "self": "https://jira.example.com/rest/api/2/priority/4", + "iconUrl": "https://jira.example.com/images/icons/priorities/minor.png", + "name": "Minor", + "id": "4" + }, + { + "self": "https://jira.example.com/rest/api/2/priority/5", + "iconUrl": "https://jira.example.com/images/icons/priorities/trivial.png", + "name": "Trivial", + "id": "5" + } + ] + }, + "labels": { + "required": false, + "schema": { + "type": "array", + "items": "string", + "system": "labels" + }, + "name": "Labels", + "autoCompleteUrl": "https://jira.example.com/rest/api/1.0/labels/suggest?query=", + "hasDefaultValue": false, + "operations": [ + "add", + "set", + "remove" + ] + } + } +} +'@ + + Mock Get-JiraIssue -ModuleName PSJira { + [PSCustomObject] @{ + ID = $issueID; + Key = $issueKey; + RestUrl = "$jiraServer/rest/api/latest/issue/$issueID"; + } + } + + It "Queries Jira for metadata information about editing an issue" { + { Get-JiraIssueEditMetadata -Issue $issueID } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/createmeta?projectIds=10003&issuetypeIds=2&expand=projects.issuetypes.fields'} + } + + It "Uses ConvertTo-JiraCreateMetaField to output EditMetaField objects if JIRA returns data" { + + # This is a simplified version of what JIRA will give back + Mock Invoke-JiraMethod -ModuleName PSJira { + @{ + fields = [PSCustomObject] @{ + 'a' = 1; + 'b' = 2; + } + } + } + Mock ConvertTo-JiraCreateMetaField -ModuleName PSJira {} + + { Get-JiraIssueEditMetadata -Issue $issueID } | Should Not Throw + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/createmeta?projectIds=10003&issuetypeIds=2&expand=projects.issuetypes.fields'} + + # There are 2 example fields in our mock above, but they should + # be passed to Convert-JiraCreateMetaField as a single object. + # The method should only be called once. + Assert-MockCalled -CommandName ConvertTo-JiraEditMetaField -ModuleName PSJira -Exactly -Times 1 -Scope It + } + } + } +} From c2f307a0121d9be23426f06e1aeeda37ba98d884 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 9 Nov 2016 14:24:05 +0100 Subject: [PATCH 4/8] Fixed naming of Unit Test file --- ...eEditMetadata.Test.ps1 => Get-JiraIssueEditMetadata.Tests.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename PSJira/Public/{Get-JiraIssueEditMetadata.Test.ps1 => Get-JiraIssueEditMetadata.Tests.ps1} (100%) diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.Test.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.Tests.ps1 similarity index 100% rename from PSJira/Public/Get-JiraIssueEditMetadata.Test.ps1 rename to PSJira/Public/Get-JiraIssueEditMetadata.Tests.ps1 From 1f361bffb4c2f2fb4af5df0bd661adac74c7f0c0 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 9 Nov 2016 15:11:11 +0100 Subject: [PATCH 5/8] fixed name of Function file --- ...rtTo-JiraEditMeraField.ps1 => ConvertTo-JiraEditMetaField.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename PSJira/Internal/{ConvertTo-JiraEditMeraField.ps1 => ConvertTo-JiraEditMetaField.ps1} (100%) diff --git a/PSJira/Internal/ConvertTo-JiraEditMeraField.ps1 b/PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 similarity index 100% rename from PSJira/Internal/ConvertTo-JiraEditMeraField.ps1 rename to PSJira/Internal/ConvertTo-JiraEditMetaField.ps1 From 62fd98f974377652b343f75e9c6f21a264bec957 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Fri, 30 Dec 2016 16:49:17 -0600 Subject: [PATCH 6/8] Corrected some URLs and typos from Create to Edit --- .vscode/tasks.cmd | 9 ++++++ .vscode/tasks.json | 29 +++++++++++++++++++ .../Get-JiraIssueEditMetadata.Tests.ps1 | 10 +++---- 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 .vscode/tasks.cmd create mode 100644 .vscode/tasks.json diff --git a/.vscode/tasks.cmd b/.vscode/tasks.cmd new file mode 100644 index 00000000..6bbe21f1 --- /dev/null +++ b/.vscode/tasks.cmd @@ -0,0 +1,9 @@ +@rem Do not edit! This file is generated by New-VSCodeTask.ps1 +@echo off +if "%1" == "!" goto start +chcp 65001 > nul +PowerShell.exe -NoProfile -ExecutionPolicy Bypass "& 'D:\Documents\Projects\PSJira\Build\Invoke-Build.ps1' -File 'D:\Documents\Projects\PSJira\Build\PSJira.build.ps1' %1" +exit +:start +shift +start PowerShell.exe -NoExit -NoProfile -ExecutionPolicy Bypass "& 'D:\Documents\Projects\PSJira\Build\Invoke-Build.ps1' -File 'D:\Documents\Projects\PSJira\Build\PSJira.build.ps1' %1" diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..ca907248 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,29 @@ +// Do not edit! This file is generated by New-VSCodeTask.ps1 +// Modify the build script instead and regenerate this file. +{ + "version": "0.1.0", + "command": ".\\.vscode\\tasks.cmd", + "suppressTaskName": false, + "showOutput": "always", + "tasks": [ + { + "isBuildCommand": true, + "taskName": "." + }, + { + "taskName": "Init" + }, + { + "taskName": "Test" + }, + { + "taskName": "Build" + }, + { + "taskName": "Deploy" + }, + { + "taskName": "?" + } + ] +} diff --git a/PSJira/Public/Get-JiraIssueEditMetadata.Tests.ps1 b/PSJira/Public/Get-JiraIssueEditMetadata.Tests.ps1 index 4b3fe270..9eea8b3d 100644 --- a/PSJira/Public/Get-JiraIssueEditMetadata.Tests.ps1 +++ b/PSJira/Public/Get-JiraIssueEditMetadata.Tests.ps1 @@ -28,7 +28,7 @@ InModuleScope PSJira { Mock Invoke-JiraMethod -ModuleName PSJira { if ($ShowMockData) { - Write-Host " Mocked Invoke-WebRequest" -ForegroundColor Cyan + Write-Host " Mocked Invoke-JiraMethod" -ForegroundColor Cyan Write-Host " [Uri] $Uri" -ForegroundColor Cyan Write-Host " [Method] $Method" -ForegroundColor Cyan } @@ -223,10 +223,10 @@ InModuleScope PSJira { It "Queries Jira for metadata information about editing an issue" { { Get-JiraIssueEditMetadata -Issue $issueID } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/createmeta?projectIds=10003&issuetypeIds=2&expand=projects.issuetypes.fields'} + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like "*/rest/api/*/issue/$issueID/editmeta"} } - It "Uses ConvertTo-JiraCreateMetaField to output EditMetaField objects if JIRA returns data" { + It "Uses ConvertTo-JiraEditMetaField to output EditMetaField objects if JIRA returns data" { # This is a simplified version of what JIRA will give back Mock Invoke-JiraMethod -ModuleName PSJira { @@ -237,10 +237,10 @@ InModuleScope PSJira { } } } - Mock ConvertTo-JiraCreateMetaField -ModuleName PSJira {} + Mock ConvertTo-JiraEditMetaField -ModuleName PSJira {} { Get-JiraIssueEditMetadata -Issue $issueID } | Should Not Throw - Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like '*/rest/api/*/issue/createmeta?projectIds=10003&issuetypeIds=2&expand=projects.issuetypes.fields'} + Assert-MockCalled -CommandName Invoke-JiraMethod -ModuleName PSJira -Exactly -Times 1 -Scope It -ParameterFilter {$Method -eq 'Get' -and $URI -like "*/rest/api/*/issue/$issueID/editmeta"} # There are 2 example fields in our mock above, but they should # be passed to Convert-JiraCreateMetaField as a single object. From d8b989fbac7bd4c45414d359f7afb3df860416c1 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Fri, 30 Dec 2016 16:56:54 -0600 Subject: [PATCH 7/8] Added InModuleScope tag Test was failing because ConvertFrom-Json2 is not defined as public, so it wasn't a known PS command when the test was run outside the scope of the module. --- .../ConvertTo-JiraEditMetaField.Tests.ps1 | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 index b225717c..db4d5b2d 100644 --- a/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 +++ b/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 @@ -2,15 +2,16 @@ $here = Split-Path -Parent $MyInvocation.MyCommand.Path $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".") . "$here\$sut" -Describe "ConvertTo-JiraEditMetaField" { - function defProp($obj, $propName, $propValue) - { - It "Defines the '$propName' property" { - $obj.$propName | Should Be $propValue +InModuleScope PSJira { + Describe "ConvertTo-JiraEditMetaField" { + function defProp($obj, $propName, $propValue) + { + It "Defines the '$propName' property" { + $obj.$propName | Should Be $propValue + } } - } - $sampleJson = @' + $sampleJson = @' { "fields": { "summary": { @@ -73,41 +74,42 @@ Describe "ConvertTo-JiraEditMetaField" { } } '@ - $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson + $sampleObject = ConvertFrom-Json2 -InputObject $sampleJson - $r = ConvertTo-JiraEditMetaField $sampleObject + $r = ConvertTo-JiraEditMetaField $sampleObject - It "Creates PSObjects out of JSON input" { - $r | Should Not BeNullOrEmpty - $r.Count | Should Be 2 - } + It "Creates PSObjects out of JSON input" { + $r | Should Not BeNullOrEmpty + $r.Count | Should Be 2 + } - It "Sets the type name to PSJira.CreateMetaField" { - # Need to use the pipeline in this case, instead of directly using the - # -InputObject parameter. This is a quirk of PowerShell, arrays, and - # the pipeline. - ($r | Get-Member).TypeName | Should Be 'PSJira.EditMetaField' - } + It "Sets the type name to PSJira.CreateMetaField" { + # Need to use the pipeline in this case, instead of directly using the + # -InputObject parameter. This is a quirk of PowerShell, arrays, and + # the pipeline. + ($r | Get-Member).TypeName | Should Be 'PSJira.EditMetaField' + } - Context "Data validation" { - # Our sample JSON includes two fields: summary and priority. - $summary = ConvertTo-JiraEditMetaField $sampleObject | Where-Object -FilterScript {$_.Name -eq 'Summary'} - $priority = ConvertTo-JiraEditMetaField $sampleObject | Where-Object -FilterScript {$_.Name -eq 'Priority'} + Context "Data validation" { + # Our sample JSON includes two fields: summary and priority. + $summary = ConvertTo-JiraEditMetaField $sampleObject | Where-Object -FilterScript {$_.Name -eq 'Summary'} + $priority = ConvertTo-JiraEditMetaField $sampleObject | Where-Object -FilterScript {$_.Name -eq 'Priority'} - defProp $summary 'Id' 'summary' - defProp $summary 'Name' 'Summary' - defProp $summary 'HasDefaultValue' $false - defProp $summary 'Required' $true - defProp $summary 'Operations' @('set') + defProp $summary 'Id' 'summary' + defProp $summary 'Name' 'Summary' + defProp $summary 'HasDefaultValue' $false + defProp $summary 'Required' $true + defProp $summary 'Operations' @('set') - It "Defines the 'Schema' property if available" { - $summary.Schema | Should Not BeNullOrEmpty - $priority.Schema | Should Not BeNullOrEmpty - } + It "Defines the 'Schema' property if available" { + $summary.Schema | Should Not BeNullOrEmpty + $priority.Schema | Should Not BeNullOrEmpty + } - It "Defines the 'AllowedValues' property if available" { - $summary.AllowedValues | Should BeNullOrEmpty - $priority.AllowedValues | Should Not BeNullOrEmpty + It "Defines the 'AllowedValues' property if available" { + $summary.AllowedValues | Should BeNullOrEmpty + $priority.AllowedValues | Should Not BeNullOrEmpty + } } } } From 3c55d95533f443c4025dc8f39172d0511d32178f Mon Sep 17 00:00:00 2001 From: Joshua T Date: Fri, 30 Dec 2016 16:58:16 -0600 Subject: [PATCH 8/8] Corrected JSON syntax and adjusted formatting There was an extra bracket at the end of the JSON {found using an external JSON tool). Also reduced the number of spaces in the JSON for convenience. --- .../ConvertTo-JiraEditMetaField.Tests.ps1 | 115 +++++++++--------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 b/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 index db4d5b2d..de77811e 100644 --- a/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 +++ b/PSJira/Internal/ConvertTo-JiraEditMetaField.Tests.ps1 @@ -13,64 +13,63 @@ InModuleScope PSJira { $sampleJson = @' { - "fields": { - "summary": { - "required": true, - "schema": { - "type": "string", - "system": "summary" - }, - "name": "Summary", - "hasDefaultValue": false, - "operations": [ - "set" - ] - }, - "priority": { - "required": false, - "schema": { - "type": "priority", - "system": "priority" - }, - "name": "Priority", - "hasDefaultValue": true, - "operations": [ - "set" - ], - "allowedValues": [ - { - "self": "http://jiraserver.example.com/rest/api/2/priority/1", - "iconUrl": "http://jiraserver.example.com/images/icons/priorities/blocker.png", - "name": "Block", - "id": "1" - }, - { - "self": "http://jiraserver.example.com/rest/api/2/priority/2", - "iconUrl": "http://jiraserver.example.com/images/icons/priorities/critical.png", - "name": "Critical", - "id": "2" - }, - { - "self": "http://jiraserver.example.com/rest/api/2/priority/3", - "iconUrl": "http://jiraserver.example.com/images/icons/priorities/major.png", - "name": "Major", - "id": "3" - }, - { - "self": "http://jiraserver.example.com/rest/api/2/priority/4", - "iconUrl": "http://jiraserver.example.com/images/icons/priorities/minor.png", - "name": "Minor", - "id": "4" - }, - { - "self": "http://jiraserver.example.com/rest/api/2/priority/5", - "iconUrl": "http://jiraserver.example.com/images/icons/priorities/trivial.png", - "name": "Trivial", - "id": "5" - } - ] - } - } + "fields": { + "summary": { + "required": true, + "schema": { + "type": "string", + "system": "summary" + }, + "name": "Summary", + "hasDefaultValue": false, + "operations": [ + "set" + ] + }, + "priority": { + "required": false, + "schema": { + "type": "priority", + "system": "priority" + }, + "name": "Priority", + "hasDefaultValue": true, + "operations": [ + "set" + ], + "allowedValues": [ + { + "self": "http://jiraserver.example.com/rest/api/2/priority/1", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/blocker.png", + "name": "Block", + "id": "1" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/2", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/critical.png", + "name": "Critical", + "id": "2" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/3", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/major.png", + "name": "Major", + "id": "3" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/4", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/minor.png", + "name": "Minor", + "id": "4" + }, + { + "self": "http://jiraserver.example.com/rest/api/2/priority/5", + "iconUrl": "http://jiraserver.example.com/images/icons/priorities/trivial.png", + "name": "Trivial", + "id": "5" + } + ] + } } } '@