src/tools/Get-DefectSuite.ps1
. "$PSScriptRoot/types/Defect.ps1" . "$PSScriptRoot/types/DefectSuite.ps1" # . "$PSScriptRoot/types/DefectResponse.ps1" $modulePath = (Get-Item $PSScriptRoot).Parent.Parent.FullName Write-Output "Installing function contained in: $PSScriptRoot" $debug = $true $hvalue = [Environment]::GetEnvironmentVariable("ZSESSIONID", "User") $header = @{"zsessionid"=$hvalue} function dsFolderPath(){ [Environment]::GetEnvironmentVariable("DS_FOLDER_PATH", "User") } function dsDataToUUID(){ param( [Parameter(ValueFromPipeline)] $dsData ) $dsData.QueryResult.Results[0]._refObjectUUID } function dsDataToName(){ param( [Parameter(ValueFromPipeline)] $dsData ) $dsData.QueryResult.Results[0]._refObjectName } function dsDataToRefUrl(){ param( [Parameter(ValueFromPipeline)] $dsData ) $dsData.QueryResult.Results[0]._ref } function getDsDataFromDsId($dsId){ Invoke-RestMethod -Uri "https://rally1.rallydev.com/slm/webservice/v2.0/DefectSuite?query=(FormattedID = $dsId)" -Headers $header | Select-Object QueryResult } function getDsFullFromRefUrl(){ param( [Parameter(ValueFromPipeline)] $refUrl ) Invoke-RestMethod -Uri $refUrl -Headers $header | Select-Object DefectSuite } # TODO: Create DS folder in dsFolderPath, create _index.md and write Ds content in there # TODO: Log operations to a file in the root dsFolderPath function createDsFolder(){ param([Parameter(ValueFromPipeline)] $dsFullData) throw NotImplementedException } function postDefect(){ param( [Parameter(ValueFromPipeline)] $defect ) if($debug){ Write-Output "Would have posted this defect: $($defect | ConvertTo-Json -Depth 3)" return } Invoke-RestMethod -Method Post -Uri "https://rally1.rallydev.com/slm/webservice/v2.0/defect/create" -Headers $header -Body $defect } function findDsFolder(){ param( [Parameter(ValueFromPipeline)] $dsId ) $directories = Get-ChildItem -Path dsFolderPath -Directory -Filter "$dsId*" if($directories.Length -gt 1){ Write-Error "There are duplicate directories for this DefectSuite." } return $directories[0] } function getDsDefects(){ param( [Parameter(ValueFromPipeline)] $dsObjectID ) $url = "https://rally1.rallydev.com/slm/webservice/v2.0/DefectSuite/$dsObjectID/Defects" # Write-Output "Invoking request: $url" (Invoke-RestMethod -Uri $url -Headers $header).QueryResult.Results | Select-Object FormattedID,Name,Description,c_ApprovedProject,c_FoundinVersion,c_VerifiedinVersion,c_Impact,c_Likelihood,Priority,c_Product,c_Activity,c_Workaround,Environment,SalesforceCaseNumber,Severity,State,Project,DefectSuites,Expedite,DisplayColor } function dsFullToDefect(){ param( [Parameter(ValueFromPipeline)] $dsFull ) $dsFull | ConvertTo-Yaml -Depth 3 | Out-File "$(dsFolderPath)/" $ds = $dsFull.DefectSuite $ds | ConvertTo-Json -Depth 3 | Write-Output @{ Name = $ds.Name Description = $ds.Description c_ApprovedProject = $ds.c_ApprovedProject c_FoundinVersion = $ds.c_FoundinVersion c_VerifiedinVersion = $ds.c_VerifiedinVersion c_Impact = $ds.c_Impact c_Likelihood = $ds.c_Likelihood Priority = $ds.Priority c_Product = $ds.c_Product c_Activity = $ds.c_Activity c_Workaround = $ds.c_Workaround Environment = $ds.Environment SalesforceCaseNumber = $ds.SalesforceCaseNumber Severity = $ds.Severity State = $ds.State Project = $ds.Project DefectSuites = $ds.DefectSuites Expedite = $ds.Expedite DisplayColor = $ds.DisplayColor } } function getVersion(){ $manifestPath = "$modulePath/RallyQuickToolsCli.psd1" $content = Get-Content $manifestPath -Raw $version = ( $content ` | Select-String "(?<=ModuleVersion = ').*(?=')" ).Matches.Value.Split('.') return $version } function getLatestVersion(){ ((Invoke-WebRequest -Uri "https://www.powershellgallery.com/packages/RallyQuickToolsCli" -Method Head).BaseResponse.RequestMessage.RequestUri.AbsolutePath -Split "/")[-1].Split('.') } function trimName(){ param( [string] $name ) if($name.IndexOfAny(":") -gt -1){ $name = ($name -split ":")[1] }else{ $dsNameArray = $name -split "-" if($dsNameArray.Length -gt 1){ $name = $dsNameArray[-1].Trim() } } ($($name) -replace "[ #/]","_" -replace "QQCatalyst","_" -replace "Support","_" -replace "_{2,10}", "_" ).Trim("_").Substring(0,50) $name } function defectResponseToDefect(){ param( [Parameter(ValueFromPipeline)][String] $dr ) return $dr | Select-Object Name,Description,c_ApprovedProject,c_FoundinVersion,c_VerifiedinVersion,c_Impact,c_Likelihood,Priority,c_Product,c_Activity,c_Workaround,Environment,SalesforceCaseNumber,Severity,State,Project,DefectSuites,Expedite,DisplayColor } function dsFullToYamlFile(){ param( [Parameter(ValueFromPipeline)] $dsFull ) $ds = $dsFull.DefectSuite $dsName = trimName($ds.Name) Write-Output "DsName: $dsName" $dsId = $($ds.FormattedID) $dsIdFolder = "$(dsFolderPath)/$dsId-$dsName" if(-not(Test-Path $dsIdFolder -PathType Container)){ Write-Output "Creating directory: $dsIdFolder/" New-Item "$dsIdFolder" -ItemType Directory } $outFile = "$dsIdFolder/dsInfo.yml" Write-Output "Writing to: $outFile" $ds | ConvertTo-Yaml | Out-File $outFile -Force if(-not(Test-Path "$dsIdFolder/_index.md")){ "# $dsName`n`n[$dsName]($($ds._ref))`n`n" ` + $ds.Description ` -replace "<p> </p>","" ` -replace "<p>","" ` -replace "</p>","`n" ` -replace "`n{3,100}","`n`n" ` | Out-File "$dsIdFolder/_index.md" } } function defectToYamlFile(){ param( [Parameter(ValueFromPipeline)] $defect ) $outFile = "$(dsFolderPath)/defect.yml" Write-Output "Writing to: $outFile" $defect | ConvertTo-Yaml | Out-File $outFile -Force } function wrapWithHtml($linkUrl, $textText){ return " <html> <body> <!--StartFragment--> <a href='$linkUrl'>$linkText</a> <!--EndFragment--> </body> </html>" } function modifyDefect(){ param( [Parameter(ValueFromPipeline)] $defect ) return $defect } <# .SYNOPSIS Provides SRE-specific handling of Rally Tickets .DESCRIPTION Manage Default Suites and defects using the following commands .PARAMETER defectSuite Required default Defect Suite id .PARAMETER copyUrlToClipboard Copy the DS URL to the Windows Clipboard for pasting anywhere .PARAMETER copyLongLinkToClipboard Copy Id and Name to HTML fragment .PARAMETER copyShortLinkToClipboard Copy Id to HTML fragment .PARAMETER triageHighPriority This will: 1. Create a new defect, cloning the information from the defect suite. a. The new Defect will have the following name structure: DS#### - SRE - Defect Suite Title b. The new Defect will be assigned to the Site Reliability Project. c. The new Defect will be attached to the Defect Suite. 2. The Defect Suite's "SRE SLA Date" will be updated to 90 days from the time you click the button to fit with our SLA. 3. The Defect Suite's "Escalation Status" will be set to "Waiting for Analysis". .PARAMETER triageLowPriority This will: 1. Create a new defect, cloning the information from the defect suite. a. The new Defect will have the following name structure: DS#### - DEV - Defect Suite Title b. The new Defect will be assigned to the correct Dev Project according to product. 2. The Defect Suite's "Escalation Status" will be set to "Backlog - Closed". .PARAMETER divertToDev This will: 1. Attempt to find the existing SRE defect and update its: "State" to "Closed" and "Schedule State" to "Accepted" and "Resolution" to "Duplicate". (If none exists it should throw an exception and do nothing else as a safety.) 2. This will create a new defect, cloning the information from the defect suite. a. The new Defect will have the following name structure: DS#### - DEV - Defect Suite Title b. The new Defect will be assigned to the correct Dev project according to product. c. The new Defect will be attached to the Defect Suite. 3. The Defect Suite will be updated to: a. Remove the current owner b. Update its status to the most relevant "waiting" option. (i.e."In analysis" => "Waiting for analysis" and "Remediation in progress" => "Waiting for remediation") c. Add the "DivertedToDev" tag .PARAMETER syncPriorityToDefects Syncronize high-priority DS .PARAMETER triageUnshieldedProductDS Triage Unsheilded Product DS .PARAMETER openInBrowser Open browser window and navigate to Defect Suite in Rally .PARAMETER calculateCycleTimes Calculate cycle times .PARAMETER dsDataToUUID Returns the UUID value for the DS .EXAMPLE #> function Get-DefectSuite { [CmdletBinding()] param( [Parameter(Position=0)] [string][alias("ds")] $dsId, [switch][alias("cu")] $copyUrlToClipboard, [switch][alias("clong")] $copyLongLinkToClipboard, [switch][alias("cshort")] $copyShortLinkToClipboard, [switch][alias("thp")] $triageHighPriority, [switch][alias("tlp")] $triageLowPriority, [switch][alias("dd")] $divertToDev, [switch][alias("sync")] $syncPriorityToDefects, [switch][alias("tu")] $triageUnshieldedProductDS, [switch][alias("web")] $openInBrowser, [switch][alias("calc")] $calculateCycleTimes, [switch][alias("uuid")] $dsDataToUUID, [switch][alias("pull")] $pullDsData, [switch][alias("h")] $help, [switch][alias("v")] $version ) $dsId = $dsId.ToUpper() if(-not $dsId -match "DS\d{3,5}"){ return Write-Output "Defect Suite id must match pattern 'DS\d{3,5}" } if($version){ $currentVersion = getVersion $latestVersion = getLatestVersion if($currentVersion[-1] -lt $latestVersion[-1]){ Write-Output "There is a newer version of RallyQuickToolsCli available" Write-Output "Your version: $($currentVersion -join '.')" Write-Output "Latest version: $($latestVersion -join '.')" Write-Output "If you would like to upgrade to the latest version type: Update-Module RallyQuickToolsCli" }else{ Write-Output "Current version is: $($currentVersion -join '.')" } } # Lookup Defect Suite if($dsId){ getDsDataFromDsId($dsId) | dsDataToName } if($dsDataToUUID){ getDsDataFromDsId($dsId) | dsDataToUUID } if($copyUrlToClipboard){ $uuid = getDsDataFromDsId($dsId) | dsDataToUUID "https://rally1.rallydev.com/#/detail/defectsuite/$uuid" | clip } if($openInBrowser){ $uuid = getDsDataFromDsId($dsId) | dsDataToUUID Start-Process "https://rally1.rallydev.com/#/detail/defectsuite/$uuid" } if($copyLongLinkToClipboard){ $dsData = getDsDataFromDsId($dsId) $linkUrl = "https://rally1.rallydev.com/#/detail/defectsuite/$($dsData | dsDataToUUID)" $linkText = "$dsId - $($dsData | dsDataToName )" wrapWithHtml($linkUrl, $linkText) | clip } if($copyShortLinkToClipboard){ $dsData = getDsDataFromDsId($dsId) $linkUrl = "https://rally1.rallydev.com/#/detail/defectsuite/$($dsData | dsDataToUUID)" wrapWithHtml($linkUrl, $dsId) | clip } if($triageHighPriority){ getDsDataFromDsId($dsId) | dsDataToRefUrl | getDsFullFromRefUrl | dsFullToDefect | modifyDefect | postDefect } if($pullDsData){ if(-not(dsFolderPath)){ return 'ERROR: No folder path set To pull data you must set a local Defect Suite folder with [Environment]::SetEnvironmentVariable("DS_FOLDER_PATH","<your_defectsuite_folder_path", "User")' } getDsDataFromDsId($dsId) | dsDataToRefUrl | getDsFullFromRefUrl | dsFullToYamlFile } if($triageLowPriority){ getDsDataFromDsId($dsId) | dsDataToRefUrl | getDsFullFromRefUrl | dsFullToDefect | defectToYamlFile } if($divertToDev){ Write-Error "Not yet implemented" } if($syncPriorityToDefects){ Write-Error "Not yet implemented" } if($triageUnshieldedProductDS){ Write-Error "Not yet implemented" } if($calculateCycleTimes){ Write-Error "Not yet implemented" } if($help){ Get-Help Get-DefectSuite } } |