From cdb46fdbc7a3b6f86266c0ebebf8b629abbbfe94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Wed, 25 Feb 2026 18:57:55 +0100 Subject: [PATCH 01/11] feat(environment): add project title handling in project parameters --- Test/private/MockCall_Project700.ps1 | 1 + .../environment/projectParameters.test.ps1 | 20 +++++++++++++++++++ public/environment/environmentCache.ps1 | 12 +++++++++++ ...ctParameters.ps1 => projectParameters.ps1} | 7 ++++++- 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Test/public/environment/projectParameters.test.ps1 rename public/environment/{resolveProjectParameters.ps1 => projectParameters.ps1} (90%) diff --git a/Test/private/MockCall_Project700.ps1 b/Test/private/MockCall_Project700.ps1 index 54d9140..fcf4032 100644 --- a/Test/private/MockCall_Project700.ps1 +++ b/Test/private/MockCall_Project700.ps1 @@ -44,6 +44,7 @@ function Get-Mock_Project_700 { # Project info $project.id = $pActual.id $project.owner = $pActual.owner.login + $project.title = $pActual.title $project.number = $pActual.number $project.url = $pActual.url $project.cacheFileName = "$($pActual.owner.login)_$($pActual.number).json" diff --git a/Test/public/environment/projectParameters.test.ps1 b/Test/public/environment/projectParameters.test.ps1 new file mode 100644 index 0000000..c2efa16 --- /dev/null +++ b/Test/public/environment/projectParameters.test.ps1 @@ -0,0 +1,20 @@ +function Test_SetProjectParameters_SUCCESS{ + + $p = Get-Mock_Project_700 ; $owner = $p.Owner ; $projectNumber = $p.Number ; $projectTitle = $p.title + MockCall_GetProject $p + $dbPath = Get-Mock_DatabaseRootPath + + # Act + Set-ProjectParameters -Owner $owner -ProjectNumber $projectNumber + + $v = @{ + Owner = @{value =$owner ; file = $($dbPath | Join-Path -Child "EnvironmentCache_Owner.json")} + ProjectNumber = @{value =$projectNumber ; file = $($dbPath | Join-Path -Child "EnvironmentCache_ProjectNumber.json")} + ProjectTitle = @{value =$projectTitle ; file = $($dbPath | Join-Path -Child "EnvironmentCache_ProjectTitle.json")} + } + + $v.keys | ForEach-Object { + $key = $_ + Assert-AreEqual -Expected $v[$key].value -Presented (Get-Content -Path $v[$key].file | ConvertFrom-Json) + } +} \ No newline at end of file diff --git a/public/environment/environmentCache.ps1 b/public/environment/environmentCache.ps1 index 2f4b911..e05d352 100644 --- a/public/environment/environmentCache.ps1 +++ b/public/environment/environmentCache.ps1 @@ -9,8 +9,13 @@ function Get-ProjectHelperEnvironment{ # Last Known Good Owner Owner = Get-EnvItem -Name "EnvironmentCache_Owner" + # Last Known Good Project Number ProjectNumber = Get-EnvItem -Name "EnvironmentCache_ProjectNumber" + + # Last known good Project Name + ProjectTitle = Get-EnvItem -Name "EnvironmentCache_ProjectTitle" + # List of fields to display on Items display commands. Useful with ConvertToItemDisplay # TODO : Consider if its worth keeping this setting DisplayFields = Get-EnvItem -Name "EnvironmentCache_Display_Fields" @@ -26,6 +31,7 @@ function Reset-ProjectHelperEnvironment{ Set-EnvItem -Name "EnvironmentCache_Owner" -Value $null Set-EnvItem -Name "EnvironmentCache_ProjectNumber" -Value $null + Set-EnvItem -Name "EnvironmentCache_ProjectTitle" -Value $null Set-EnvItem -Name "EnvironmentCache_Display_Fields" -Value $null } Export-ModuleMember -Function Reset-ProjectHelperEnvironment @@ -35,6 +41,7 @@ function Set-ProjectHelperEnvironment{ param( [Parameter(ValueFromPipelineByPropertyName)][string]$Owner, [Parameter(ValueFromPipelineByPropertyName)][string]$ProjectNumber, + [Parameter(ValueFromPipelineByPropertyName)][string]$ProjectTitle, [Parameter(ValueFromPipelineByPropertyName)][string[]]$DisplayFields ) @@ -45,6 +52,11 @@ function Set-ProjectHelperEnvironment{ if(! [string]::IsNullOrWhiteSpace($ProjectNumber)) { Set-EnvItem -Name "EnvironmentCache_ProjectNumber" -Value $ProjectNumber } + + if(! [string]::IsNullOrWhiteSpace($ProjectTitle)) { + Set-EnvItem -Name "EnvironmentCache_ProjectTitle" -Value $ProjectTitle + } + if($DisplayFields) { Set-EnvItem -Name "EnvironmentCache_Display_Fields" -Value $DisplayFields } diff --git a/public/environment/resolveProjectParameters.ps1 b/public/environment/projectParameters.ps1 similarity index 90% rename from public/environment/resolveProjectParameters.ps1 rename to public/environment/projectParameters.ps1 index 3257ce1..da79c85 100644 --- a/public/environment/resolveProjectParameters.ps1 +++ b/public/environment/projectParameters.ps1 @@ -52,8 +52,13 @@ function Set-ProjectParameters { ) process { + $db = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber -ErrorAction SilentlyContinue - Set-ProjectHelperEnvironment -Owner $Owner -ProjectNumber $ProjectNumber + if($db){ + $ProjectTitle = $db.title + } + + Set-ProjectHelperEnvironment -Owner $Owner -ProjectNumber $ProjectNumber -ProjectTitle $ProjectTitle } } Export-ModuleMember -Function Set-ProjectParameters -Alias "Set-Project" \ No newline at end of file From 89c8fb74c1efcb41f48d9fe88baf6f37da90593c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Wed, 25 Feb 2026 20:43:41 +0100 Subject: [PATCH 02/11] feat(prompt): add projecttitle to the prompt --- public/environment/projectParameters.ps1 | 4 +- public/prompt/getPrompt.ps1 | 56 +++++++++++++++++++----- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/public/environment/projectParameters.ps1 b/public/environment/projectParameters.ps1 index da79c85..86ff7e2 100644 --- a/public/environment/projectParameters.ps1 +++ b/public/environment/projectParameters.ps1 @@ -45,7 +45,7 @@ function Test-ProjectParameters { function Set-ProjectParameters { [CmdletBinding()] - [Alias("Set-Project")] + [Alias("Set-Project","spp")] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName, Position = 0)][string]$Owner, [Parameter(Mandatory,ValueFromPipelineByPropertyName, Position = 1)][string]$ProjectNumber @@ -61,4 +61,4 @@ function Set-ProjectParameters { Set-ProjectHelperEnvironment -Owner $Owner -ProjectNumber $ProjectNumber -ProjectTitle $ProjectTitle } -} Export-ModuleMember -Function Set-ProjectParameters -Alias "Set-Project" \ No newline at end of file +} Export-ModuleMember -Function Set-ProjectParameters -Alias "Set-Project","spp" \ No newline at end of file diff --git a/public/prompt/getPrompt.ps1 b/public/prompt/getPrompt.ps1 index e73d4ff..36bd53f 100644 --- a/public/prompt/getPrompt.ps1 +++ b/public/prompt/getPrompt.ps1 @@ -4,19 +4,46 @@ This file contains functions to control ProjectHelper prompt. #> +Set-MyInvokeCommandAlias -Alias ProjectHelperPromptSettingsVariableName -Command "echo ProjecthelperPromoptSettings" + +function GetProjectHelperPromptSettings { + + $variable = Invoke-MyCommand -Command "ProjectHelperPromptSettingsVariableName" + + $s = Get-Variable -Name $variable -Scope Global -ErrorAction SilentlyContinue + + if($s) { + $ret = $s.Value + } else { + $ret = @{} + } + + return $ret +} + +function SetProjectHelperPromptSettings($value) { + $variable = Invoke-MyCommand -Command "ProjectHelperPromptSettingsVariableName" + + $value.Guid = (New-Guid).ToString() + + Set-Variable -Name $variable -Value $value -Scope Global + +} + function Initialize-ProjectHelperPromptSettings { [CmdletBinding()] param( [switch]$Force ) - if($global:ProjecthelperPromoptSettings -and -not $Force) { + $s = GetProjectHelperPromptSettings + + if($($s.Guid) -and -not $Force) { Write-Verbose "ProjecthelperPromoptSettings already initialized, skipping initialization." return } - $global:ProjecthelperPromoptSettings = @{ - Guid = (New-Guid).ToString() + $s = @{ HidePrompt = $false Verbose = $false PreviousPromptGit = '`n' @@ -29,23 +56,30 @@ function Initialize-ProjectHelperPromptSettings { AfterStatus = [PSCustomObject] @{ PreText = ']' ; ForegroundColor = 'Yellow' ; BackgroundColor = 'Black' } OwnerStatus = [PSCustomObject] @{ PreText = '' ; ForegroundColor = 'DarkCyan' ; BackgroundColor = 'Black' } NumberStatus = [PSCustomObject] @{ PreText = '#' ; ForegroundColor = 'DarkMagenta' ; BackgroundColor = 'Black' } + TitleStatus = [PSCustomObject] @{ PreText = '' ; ForegroundColor = 'DarkGreen' ; BackgroundColor = 'Black' } SpaceStatus = [PSCustomObject] @{ PreText = ' ' ; ForegroundColor = 'Black' ; BackgroundColor = 'Black' } OKStatus = [PSCustomObject] @{ PreText = '≡' ; ForegroundColor = 'Green' ; BackgroundColor = 'Black' } KOStatus = [PSCustomObject] @{ PreText = '!' ; ForegroundColor = 'white' ; BackgroundColor = 'Red' } NewlineStatus = [PSCustomObject] @{ PreText = '`n' ; ForegroundColor = 'Black' ; BackgroundColor = 'Black' } } -} Export-ModuleMember -Function Reset-ProjectHelperPromptSettings + + SetProjectHelperPromptSettings -value $s + +} Export-ModuleMember -Function Initialize-ProjectHelperPromptSettings function Get-ProjecthelperPromptSettings { [CmdletBinding()] param() - if (-not $global:ProjecthelperPromoptSettings) { + $s = GetProjectHelperPromptSettings + + if (-not $s.Guid) { Write-Verbose "ProjecthelperPromoptSettings not initialized, initializing now." Initialize-ProjectHelperPromptSettings + $s = GetProjectHelperPromptSettings } - return $global:ProjecthelperPromoptSettings + return $s } function Write-ProjecthelperPrompt { @@ -63,15 +97,15 @@ function Write-ProjecthelperPrompt { return $null } - "hola" | Write-Verbose - $env = Get-ProjectHelperEnvironment $owner = $env.Owner $projectNumber = $env.ProjectNumber + $projectTitle = $env.ProjectTitle "Owner : $owner" | Write-Verbose "ProjectNumber : $projectNumber" | Write-Verbose + "ProjectTitle : $projectTitle" | Write-Verbose if (-not $owner -and -not $projectNumber) { return $null @@ -91,6 +125,8 @@ function Write-ProjecthelperPrompt { $s.DelimStatus1 | Write-HostPrompt $s.NumberStatus | Write-HostPrompt $projectNumber $s.DelimStatus2 | Write-HostPrompt + $s.TitleStatus | Write-HostPrompt $projectTitle + $s.DelimStatus2 | Write-HostPrompt $countColor | Write-HostPrompt $countText $s.AfterStatus | Write-HostPrompt $s.SpaceStatus | Write-HostPrompt @@ -219,7 +255,7 @@ function Show-ProjecthelperPrompt{ [CmdletBinding()] param() - $s = $ProjecthelperPromoptSettings + $s = GetProjecthelperPromptSettings $s.HidePrompt = $false } Export-ModuleMember -Function Show-ProjecthelperPrompt @@ -227,7 +263,7 @@ function Hide-ProjecthelperPrompt{ [CmdletBinding()] param() - $s = Get-ProjecthelperPromptSettings + $s = GetProjecthelperPromptSettings $s.HidePrompt = $true } Export-ModuleMember -Function Hide-ProjecthelperPrompt From a02901d2094c899f0fbf2221fe57482210d2d037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Wed, 25 Feb 2026 20:46:46 +0100 Subject: [PATCH 03/11] feat(test): test fro adding projecttitle to prompt --- Test/private/MockCall_Project.ps1 | 1 + Test/public/getPrompt.test.ps1 | 43 ++++++++++++++++++++----------- Test/traceInvoke.log | 1 + 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Test/private/MockCall_Project.ps1 b/Test/private/MockCall_Project.ps1 index cc31a13..9af91af 100644 --- a/Test/private/MockCall_Project.ps1 +++ b/Test/private/MockCall_Project.ps1 @@ -20,6 +20,7 @@ function Get-Mock_Project_625 { $project.id = $p.id $project.owner = $p.owner.login $project.number = $p.number + $project.title = $p.title $project.url = $p.url # Add Items to mock diff --git a/Test/public/getPrompt.test.ps1 b/Test/public/getPrompt.test.ps1 index fae2b88..0c81ccc 100644 --- a/Test/public/getPrompt.test.ps1 +++ b/Test/public/getPrompt.test.ps1 @@ -1,8 +1,11 @@ function Test_GetProjecthelperPrompt { - $owner = "octodemo" - $projectNumber = "625" - $s = $ProjecthelperPromoptSettings + $p = Get-Mock_Project_625 ; $owner = $p.owner ; $projectNumber = $p.number ; $projectTitle = $p.title + MockCall_GetProject -MockProject $p + + $Mock_ProjectHelperPromptSettingsVariableName = "Mock_ProjectHelperPromptSettingsVariableName" + Clear-Variable -Name $Mock_ProjectHelperPromptSettingsVariableName -Scope Global -ErrorAction SilentlyContinue + MockCallToString -Command "echo ProjecthelperPromoptSettings" -OutString $Mock_ProjectHelperPromptSettingsVariableName MockCall_GitHubOrgProjectWithFields -Owner $owner -ProjectNumber $projectNumber -FileName "invoke-GitHubOrgProjectWithFields-octodemo-625-skipitems.json" -SkipItems MockCallJson -Command 'Invoke-GetItem -itemid id1' -FileName "invoke-getitem-id1.json" @@ -17,21 +20,27 @@ function Test_GetProjecthelperPrompt { Assert-IsNull -Object $(($result | select-string -Pattern "^\[$" ).LineNumber) # Set environment with empty values - Set-ProjectHelperEnvironment -Owner $owner -ProjectNumber $projectNumber + Set-ProjectParameters -Owner $owner -ProjectNumber $projectNumber # With environment, without new line $result = Invoke-WriteProjecthelperPrompt # Find the line with '[' character $resultLine = ($result | select-string -Pattern "^\[$" ).LineNumber + $s = (Get-Variable -Name $Mock_ProjectHelperPromptSettingsVariableName -Scope Global).Value + Assert-AreEqual -Presented $result[$resultLine - 1] -Expected $s.BeforeStatus.PreText Assert-AreEqual -Presented $result[$resultLine] -Expected $($($s.OwnerStatus.PreText)+$owner) Assert-AreEqual -Presented $result[$resultLine + 1] -Expected $s.DelimStatus1.PreText Assert-AreEqual -Presented $result[$resultLine + 2] -Expected $($($s.NumberStatus.PreText)+$projectNumber) Assert-AreEqual -Presented $result[$resultLine + 3] -Expected "" # $s.DelimStatus2.PreText is " " that is converted to "" by posh-git" - Assert-AreEqual -Presented $result[$resultLine + 4] -Expected $s.OKStatus.PreText - Assert-AreEqual -Presented $result[$resultLine + 5] -Expected $s.AfterStatus.PreText - Assert-AreEqual -Presented $result[$resultLine + 6] -Expected "" # $s.SpaceStatus.PreText " " that is converted to "" by posh-git + + Assert-AreEqual -Presented $result[$resultLine + 4] -Expected $($($s.TitleStatus.PreText)+$projectTitle) + Assert-AreEqual -Presented $result[$resultLine + 5] -Expected "" # $s.DelimStatus2.PreText is " " that is converted to "" by posh-git" + + Assert-AreEqual -Presented $result[$resultLine + 6] -Expected $s.OKStatus.PreText + Assert-AreEqual -Presented $result[$resultLine + 7] -Expected $s.AfterStatus.PreText + Assert-AreEqual -Presented $result[$resultLine + 8] -Expected "" # $s.SpaceStatus.PreText " " that is converted to "" by posh-git # With environment, without new line $result = Invoke-WriteProjecthelperPrompt -withnewline @@ -43,24 +52,28 @@ function Test_GetProjecthelperPrompt { Assert-AreEqual -Presented $result[$resultLine + 1] -Expected $s.DelimStatus1.PreText Assert-AreEqual -Presented $result[$resultLine + 2] -Expected $($($s.NumberStatus.PreText)+$projectNumber) Assert-AreEqual -Presented $result[$resultLine + 3] -Expected "" # $s.DelimStatus2.PreText is " " that is converted to "" by posh-git" - Assert-AreEqual -Presented $result[$resultLine + 4] -Expected $s.OKStatus.PreText - Assert-AreEqual -Presented $result[$resultLine + 5] -Expected $s.AfterStatus.PreText - Assert-AreEqual -Presented $result[$resultLine + 6] -Expected "" # SpaceStatus.PreText - Assert-AreEqual -Presented $result[$resultLine + 7] -Expected $s.NewlineStatus.PreText + + Assert-AreEqual -Presented $result[$resultLine + 4] -Expected $($($s.TitleStatus.PreText)+$projectTitle) + Assert-AreEqual -Presented $result[$resultLine + 5] -Expected "" # $s.DelimStatus2.PreText is " " that is converted to "" by posh-git" + + Assert-AreEqual -Presented $result[$resultLine + 6] -Expected $s.OKStatus.PreText + Assert-AreEqual -Presented $result[$resultLine + 7] -Expected $s.AfterStatus.PreText + Assert-AreEqual -Presented $result[$resultLine + 8] -Expected "" # SpaceStatus.PreText + Assert-AreEqual -Presented $result[$resultLine + 9] -Expected $s.NewlineStatus.PreText # Add some staged items Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId "id1" -FieldName "sf_Text1" -Value "value1" - Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId "id1" -FieldName "sf_Text2" -Value "value2" + # Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId "id1" -FieldName "sf_Text2" -Value "value2" Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId "id2" -FieldName "sf_Text1" -Value "value1" - Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId "id2" -FieldName "sf_Text2" -Value "value2" - $itemstaged = 4 + # Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId "id2" -FieldName "sf_Text2" -Value "value2" + $itemstaged = 2 # With items staged $result = Invoke-WriteProjecthelperPrompt # Find the line with '[' character $resultLine = ($result | select-string -Pattern "^\[$" ).LineNumber - Assert-AreEqual -Presented $result[$resultLine + 4] -Expected $($($s.KOStatus.PreText)+$itemstaged) + Assert-AreEqual -Presented $result[$resultLine + 6] -Expected $($($s.KOStatus.PreText)+$itemstaged) } diff --git a/Test/traceInvoke.log b/Test/traceInvoke.log index b0266c8..96a3c7d 100644 --- a/Test/traceInvoke.log +++ b/Test/traceInvoke.log @@ -81,3 +81,4 @@ Invoke-UpdateProjectV2Collaborators -ProjectId PVT_kwDOAlIw4c4BCe3V -collaborato Invoke-GitHubOrgProjectWithFields -Owner octodemo -ProjectNumber 700 -afterFields "" -afterItems "" -query "updated:>=2024-02-18" Invoke-GitHubOrgProjectWithFields -Owner octodemo -ProjectNumber 700 -afterFields "" -afterItems "" -query "updated:>=2025-03-15" Invoke-ProjectHelperOpenUrl -Url https://github.com/octodemo/rulasg-dev-1/issues/26 +echo ProjecthelperPromoptSettings From 3908141319ee56dbfbff8e930b2411bbed99ea1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Fri, 27 Feb 2026 12:00:12 +0100 Subject: [PATCH 04/11] feat(issue): add Copy-ProjectIssue function for issue duplication --- Test/public/issues/New-ProjectIssue.test.ps1 | 51 ++++++++++++++++++++ public/issues/New-ProjectIssue.ps1 | 50 ++++++++++++++++++- 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/Test/public/issues/New-ProjectIssue.test.ps1 b/Test/public/issues/New-ProjectIssue.test.ps1 index fbd32a2..5d7a57a 100644 --- a/Test/public/issues/New-ProjectIssue.test.ps1 +++ b/Test/public/issues/New-ProjectIssue.test.ps1 @@ -56,3 +56,54 @@ function Test_NewProjectIssue{ Assert-AreEqual -Expected $result -Presented $i.itemId } + +function Test_CopyProjectIssue_SUCCESS { + + $p = Get-Mock_Project_700 ; $owner = $p.owner ; $projectNumber = $p.number + $r = $p.repo + $i = $p.issueToCreateAddAndRemove + $sourceItemId = $p.issue.id + + MockCall_GetProject $p -cache + + $createString = 'Invoke-CreateIssue -RepositoryId {repoid} -Title "{title}" -Body "{body}"' + $createString = $createString -replace "{repoid}", $r.id + $createString = $createString -replace "{title}", $i.title + $createString = $createString -replace "{body}", $i.body + + MockCallJson -Command "Invoke-Repository -Owner $($r.owner) -Name $($r.name)" -FileName $r.getRepoMockFile + MockCallToObject -Command $createString -OutObject @{ data = @{ createIssue = @{ issue = @{ url = $i.url } } } } + MockCallJson -Command "Invoke-GetIssueOrPullRequest -Url $($i.url)" -FileName $i.getIssueOrPullRequestMockFile + MockCallJson -Command "Invoke-AddItemToProject -ProjectId $($p.id) -ContentId $($i.id)" -FileName $i.addIssueToOProjectMockFile + + # Act + $result = Copy-ProjectIssue -ItemId $sourceItemId -ProjectOwner $owner -ProjectNumber $projectNumber -RepoOwner $r.owner -RepoName $r.name + + # Assert + Assert-AreEqual -Expected $i.itemId -Presented $result +} + +function Test_CopyProjectIssue_SUCCESS_DoNotAddToProject { + + $p = Get-Mock_Project_700 ; $owner = $p.owner ; $projectNumber = $p.number + $r = $p.repo + $i = $p.issueToCreateAddAndRemove + $sourceItemId = $p.issue.id + + MockCall_GetProject $p -cache + + $createString = 'Invoke-CreateIssue -RepositoryId {repoid} -Title "{title}" -Body "{body}"' + $createString = $createString -replace "{repoid}", $r.id + $createString = $createString -replace "{title}", $i.title + $createString = $createString -replace "{body}", $i.body + + MockCallJson -Command "Invoke-Repository -Owner $($r.owner) -Name $($r.name)" -FileName $r.getRepoMockFile + MockCallToObject -Command $createString -OutObject @{ data = @{ createIssue = @{ issue = @{ url = $i.url } } } } + + # Act + $result = Copy-ProjectIssue -ItemId $sourceItemId -ProjectOwner $owner -ProjectNumber $projectNumber -RepoOwner $r.owner -RepoName $r.name -DoNotAddToProject + + # Assert + Assert-AreEqual -Expected $sourceItemId -Presented $result + +} diff --git a/public/issues/New-ProjectIssue.ps1 b/public/issues/New-ProjectIssue.ps1 index a237450..520caf7 100644 --- a/public/issues/New-ProjectIssue.ps1 +++ b/public/issues/New-ProjectIssue.ps1 @@ -82,4 +82,52 @@ function New-ProjectIssue { throw "Error creating issue and adding to project: $_" } -} Export-ModuleMember -Function New-ProjectIssue -Alias npi \ No newline at end of file +} Export-ModuleMember -Function New-ProjectIssue -Alias npi + +function Copy-ProjectIssue { + [CmdletBinding()] + param( + #Source Item + [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0)][Alias("id")][string]$ItemId, + #ProjectOwner + [Parameter()][string]$ProjectOwner, + [Parameter()][string]$ProjectNumber, + [Parameter(Mandatory, Position = 1)][string]$RepoOwner, + [Parameter(Mandatory, Position = 2)][string]$RepoName, + [Parameter()][switch]$OpenOnCreation, + [Parameter()][switch]$DoNotAddToProject + + ) + + try{ + # Get Project + ($ProjectOwner,$ProjectNumber) = Resolve-ProjectParameters -Owner $ProjectOwner -ProjectNumber $ProjectNumber + + $sourceItem = Get-ProjectItem -Owner $ProjectOwner -ProjectNumber $ProjectNumber -ItemId $ItemId + $title = $sourceItem.Title + $body = $sourceItem.Body + + # Create Issue + $url = New-ProjectIssueDirect -RepoOwner $RepoOwner -RepoName $RepoName -Title $title -Body $body + + if(! $url ){ + "Issue could not be created" | Write-MyError + return $null + } + + if(-Not $DoNotAddToProject){ + # Add issue to project + $itemId = Add-ProjectItem -Owner $ProjectOwner -ProjectNumber $ProjectNumber -Url $url + } + + if( $OpenOnCreation ) { + Open-Url $url + } + + return $itemId + } + catch{ + throw "Error creating issue and adding to project: $_" + } + +} Export-ModuleMember -Function Copy-ProjectIssue \ No newline at end of file From 7e8a80b38c65358bf1e65c36753a9c5ab1210a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 07:12:29 +0100 Subject: [PATCH 05/11] fix(database): add sanity check for item projectUrl to prevent saving errors --- private/projectDatabase/project_database_update.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/private/projectDatabase/project_database_update.ps1 b/private/projectDatabase/project_database_update.ps1 index 45241b1..4aa8835 100644 --- a/private/projectDatabase/project_database_update.ps1 +++ b/private/projectDatabase/project_database_update.ps1 @@ -93,6 +93,16 @@ function Update-ProjectDatabase { $actualItems = $actualprj.items ?? $(New-HashTable) foreach($itemKey in $items.Keys){ + + # Sanity check : We need to confirm that the item projectUrl field is the same as project url + # We are detecting a bug that sometimes we are saving items in the wrong database. + # Need to keep this check until we fix this bug. + if($items.$itemKey.projectUrl -ne $actualItems.$itemKey.projectUrl){ + #break in debugger + Write-Debug "Item projectUrl mismatch for key [$itemKey]" + Wait-Debugger + } + $actualItems.$itemKey = $items.$itemKey } $items = $actualItems From cd299b0a01f5472f26f8021fae66057c74f3c268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 07:14:07 +0100 Subject: [PATCH 06/11] feat(issue): add issue creation command for development --- Test/private/MockCall_Project700.ps1 | 2 ++ Test/traceInvoke.log | 1 + 2 files changed, 3 insertions(+) diff --git a/Test/private/MockCall_Project700.ps1 b/Test/private/MockCall_Project700.ps1 index fcf4032..661a6b0 100644 --- a/Test/private/MockCall_Project700.ps1 +++ b/Test/private/MockCall_Project700.ps1 @@ -70,6 +70,8 @@ function Get-Mock_Project_700 { $project.issueToCreateAddAndRemove= @{ id = $id number = 46 + title = "Issue for development" + body = "Body of issue for development" url = "https://github.com/octodemo/rulasg-dev-1/issues/46" getIssueOrPullRequestMockFile = "invoke-getissueorpullrequest-46.json" itemId = $itemId diff --git a/Test/traceInvoke.log b/Test/traceInvoke.log index 96a3c7d..41188c6 100644 --- a/Test/traceInvoke.log +++ b/Test/traceInvoke.log @@ -82,3 +82,4 @@ Invoke-GitHubOrgProjectWithFields -Owner octodemo -ProjectNumber 700 -afterField Invoke-GitHubOrgProjectWithFields -Owner octodemo -ProjectNumber 700 -afterFields "" -afterItems "" -query "updated:>=2025-03-15" Invoke-ProjectHelperOpenUrl -Url https://github.com/octodemo/rulasg-dev-1/issues/26 echo ProjecthelperPromoptSettings +Invoke-CreateIssue -RepositoryId R_kgDOPrRnkQ -Title "Issue for development" -Body "Body of issue for development" From a392250ce41a0dba7949cbc5068dbd84d980c86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 08:26:34 +0100 Subject: [PATCH 07/11] fix(test): update mock project reference in GetProjectItemUrl test --- Test/public/project_item.test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/public/project_item.test.ps1 b/Test/public/project_item.test.ps1 index f870acc..4b0cd6f 100644 --- a/Test/public/project_item.test.ps1 +++ b/Test/public/project_item.test.ps1 @@ -126,7 +126,7 @@ function Test_GetProjectItemUrl_SUCCESS_FromApiWhenMissingInCache { # Arrange Reset-InvokeCommandMock - $p = Get-Mock_Project_700 ; $owner = $p.owner ; $projectNumber = $p.number + $p = Get-Mock_Project_625 ; $owner = $p.owner ; $projectNumber = $p.number $itemId = "id1" MockCall_GetProject -MockProject $p -SkipItems MockCallJson -Command "Invoke-GetItem -itemid $itemId" -FileName "invoke-getitem-id1.json" From 1cf4f216d7b51a59552c77c61bac7601cb918bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 08:40:42 +0100 Subject: [PATCH 08/11] fix(database): enhance item validation and update handling in project database functions --- private/projectDatabase/project_database.ps1 | 22 ++++++++++------ .../projectDatabase/project_database_Item.ps1 | 6 +++++ .../project_database_update.ps1 | 25 ++++++------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/private/projectDatabase/project_database.ps1 b/private/projectDatabase/project_database.ps1 index 04506ba..9a60638 100644 --- a/private/projectDatabase/project_database.ps1 +++ b/private/projectDatabase/project_database.ps1 @@ -76,8 +76,8 @@ function Save-ProjectV2toDatabase{ param( [Parameter(Position = 0)][object]$ProjectV2, [Parameter(Position = 1)][hashtable]$Items, - [Parameter(Position = 2)][Object[]]$Fields, - [Parameter()][switch]$ItemsUpdate + [Parameter(Position = 1)][hashtable]$QueryItems, + [Parameter(Position = 2)][Object[]]$Fields ) $owner = $ProjectV2.owner.login @@ -96,14 +96,15 @@ function Save-ProjectV2toDatabase{ $db.owner = $owner $db.number = $projectnumber - if($ItemsUpdate){ + # Full list update + $db.items = $Items + + # Update just a few items + if($QueryItems){ # Update each of the items to avoid replacing all - foreach ($item in $items.Values){ + foreach ($item in $QueryItems.Values){ Set-Item $db $item } - } else { - # Add items - $db.items = $Items } # Update fields @@ -162,6 +163,13 @@ function Get-DatabaseKey{ [Parameter(Position = 1)][int]$ProjectNumber ) + if([string]::IsNullOrWhiteSpace($Owner)){ + throw "Owner is null or empty" + } + if($ProjectNumber -le 0){ + throw "ProjectNumber is null or not a positive integer" + } + $ret = "$($owner)_$($projectnumber)" return $ret diff --git a/private/projectDatabase/project_database_Item.ps1 b/private/projectDatabase/project_database_Item.ps1 index ddb5d66..61ed06a 100644 --- a/private/projectDatabase/project_database_Item.ps1 +++ b/private/projectDatabase/project_database_Item.ps1 @@ -137,6 +137,12 @@ function Set-Item{ $db = New-HashTable } + # Add Sanity check for item + # Ensure that we are adding an item to the proper project database + if($Database.ProjectId -ne $Item.projectId){ + Wait-Debugger + } + $items = $db | AddHashLink items $items.$($Item.id) = $Item diff --git a/private/projectDatabase/project_database_update.ps1 b/private/projectDatabase/project_database_update.ps1 index 4aa8835..b7c3ca2 100644 --- a/private/projectDatabase/project_database_update.ps1 +++ b/private/projectDatabase/project_database_update.ps1 @@ -15,6 +15,9 @@ function Update-ProjectDatabase { $params = @{ owner = $Owner ; projectnumber = $ProjectNumber ; afterFields = "" ; afterItems = "" ; query = "$query" } + # We new if this is a partial update + $isQuery = -Not [string]::IsNullOrEmpty($Query) + # This means that the ProjectNumber has a empty string value if($ProjectNumber -eq 0){ throw "ProjectNumber invalid. Please specify a valid ProjectNumber" @@ -86,26 +89,14 @@ function Update-ProjectDatabase { # If query is set we are updating just a few items from the database. # update just this items - if( -Not [string]::IsNullOrEmpty($Query)){ + if( $isQuery ){ + $queryItems = $items + $actualprj = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber # Check if project has no items or the project is not cached yet - $actualItems = $actualprj.items ?? $(New-HashTable) - - foreach($itemKey in $items.Keys){ + $items = $actualprj.items ?? $(New-HashTable) - # Sanity check : We need to confirm that the item projectUrl field is the same as project url - # We are detecting a bug that sometimes we are saving items in the wrong database. - # Need to keep this check until we fix this bug. - if($items.$itemKey.projectUrl -ne $actualItems.$itemKey.projectUrl){ - #break in debugger - Write-Debug "Item projectUrl mismatch for key [$itemKey]" - Wait-Debugger - } - - $actualItems.$itemKey = $items.$itemKey - } - $items = $actualItems } # If we are Skiping items on the update we need to keep the existing items in the database and just update the fields @@ -119,7 +110,7 @@ function Update-ProjectDatabase { } # Save ProjectV2 object to ProjectDatabase - Save-ProjectV2toDatabase $projectV2 -Items $items -Fields $fields + Save-ProjectV2toDatabase $projectV2 -Items $items -Fields $fields -QueryItems $queryItems return $true } Export-ModuleMember -Function Update-ProjectDatabase From b4ed494c112a8b818ccf771fb0500a0bec217a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 19:31:41 +0100 Subject: [PATCH 09/11] fix(test): enhance draft issue handling and URL generation in user order tests --- Test/private/MockCall_Project700.ps1 | 2 ++ Test/public/items/use_order.test.ps1 | 25 ++++++++++++++++++++++++- include/openFilesUrls.ps1 | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Test/private/MockCall_Project700.ps1 b/Test/private/MockCall_Project700.ps1 index 661a6b0..e0ea116 100644 --- a/Test/private/MockCall_Project700.ps1 +++ b/Test/private/MockCall_Project700.ps1 @@ -129,7 +129,9 @@ function Get-Mock_Project_700 { $draftIssue = $pActual.items.nodes | Where-Object { $_.content.title -eq "DraftIssue for development" } $fss = $draftIssue.fieldValues.nodes | Where-Object { $_.field.id -eq $($fieldsingleselect.id) } $project.draftissue = @{ + order = 11 # order of this item when calling spi id = $draftIssue.id + url = "https://github.com/orgs/$($project.owner)/projects/$($project.number)/views/1?pane=issue&itemId=$($draftIssue.fullDatabaseId)" contentId = $draftIssue.content.id title = $draftIssue.content.title status = ($draftIssue.fieldValues.nodes | Where-Object { $_.field.name -eq "Status" }).name diff --git a/Test/public/items/use_order.test.ps1 b/Test/public/items/use_order.test.ps1 index bcd50d5..96f0bf3 100644 --- a/Test/public/items/use_order.test.ps1 +++ b/Test/public/items/use_order.test.ps1 @@ -52,7 +52,30 @@ function Test_UserOrder_Success_OpenBrowser{ $p = Get-Mock_Project_700 ; $owner = $p.owner ; $projectNumber = $p.number $order = $p.issue.order ; $url = $p.issue.url - MockCallToNull -command "Invoke-ProjectHelperOpenUrl -Url $url" + $command = 'Invoke-ProjectHelperOpenUrl -Url "{url}"' + $command = $command -replace "{url}", $url + MockCallToNull -command $command + + # We need to have the environment set to get item details in PassThru + Set-ProjectHelperEnvironment -Owner $owner -ProjectNumber $projectNumber + $list = Search-ProjectItem -IncludeDone + + # Act + $result = $list | Use-Order $order -OpenInBrowser + + # Assert + Assert-IsNull -Object $result +} + +function Test_UserOrder_Success_OpenBrowser_DRAFT{ + MockCall_GetProject_700 + + $p = Get-Mock_Project_700 ; $owner = $p.owner ; $projectNumber = $p.number + $order = $p.draftissue.order ; $url = $p.draftissue.url + + $command = 'Invoke-ProjectHelperOpenUrl -Url "{url}"' + $command = $command -replace "{url}", $url + MockCallToNull -command $command # We need to have the environment set to get item details in PassThru Set-ProjectHelperEnvironment -Owner $owner -ProjectNumber $projectNumber diff --git a/include/openFilesUrls.ps1 b/include/openFilesUrls.ps1 index 7306bc7..033269d 100644 --- a/include/openFilesUrls.ps1 +++ b/include/openFilesUrls.ps1 @@ -3,7 +3,7 @@ # Provides controls to open files and URLs in the default system applications. # Use $MODULE_NAME variable to set up functions names -Set-MyInvokeCommandAlias -Alias OpenUrl -Command "Invoke-$($MODULE_NAME)OpenUrl -Url {url}" +Set-MyInvokeCommandAlias -Alias OpenUrl -Command $('Invoke-{modulename}OpenUrl -Url "{url}"' -replace "{modulename}", $MODULE_NAME) function Invoke-ModuleNameOpenUrl{ [CmdletBinding()] From ccdf113318f56f450a1071acecd89b6e03325c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 20:54:23 +0100 Subject: [PATCH 10/11] docs(prompt): update ProjectHelperPromptSettings configuration guide with detailed segment information --- public/prompt/getPrompt.ps1 | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/public/prompt/getPrompt.ps1 b/public/prompt/getPrompt.ps1 index 36bd53f..70f4904 100644 --- a/public/prompt/getPrompt.ps1 +++ b/public/prompt/getPrompt.ps1 @@ -2,6 +2,70 @@ <# .DESCRIPTION This file contains functions to control ProjectHelper prompt. + +# ProjectHelperPromptSettings Configuration Guide +# ================================================= +# +# The prompt is rendered by composing multiple segments, each defined as a +# PSCustomObject with three properties: +# PreText - Literal text prepended to the segment value +# ForegroundColor - Text color (any [ConsoleColor] name) +# BackgroundColor - Background color (any [ConsoleColor] name) +# +# Example output: [github#9279 rulasg-Work&Dev ≡] +# │ │ │ │ │ │││ +# │ │ │ │ │ ││└─ SpaceStatus (' ') +# │ │ │ │ │ │└── AfterStatus (']') +# │ │ │ │ │ └─── OKStatus ('≡') or KOStatus ('!' + count) +# │ │ │ │ └─────────────────── TitleStatus (project title) +# │ │ │ └────────────────────── DelimStatus2 (' ' separator) +# │ │ └───────────────────────── NumberStatus ('#' + project number) +# │ └───────────────────────────── DelimStatus1 (separator after owner) +# │ └───────────────────────────── OwnerStatus (owner name) +# └──────────────────────────────── BeforeStatus ('[') +# +# Segment render order (left to right): +# BeforeStatus → OwnerStatus → DelimStatus1 → NumberStatus → DelimStatus2 +# → TitleStatus → DelimStatus2 → OKStatus/KOStatus → AfterStatus → SpaceStatus +# +# Segment defaults (set in Initialize-ProjectHelperPromptSettings): +# BeforeStatus = @{ PreText = '[' ; ForegroundColor = 'Yellow' ; BackgroundColor = 'Black' } +# OwnerStatus = @{ PreText = '' ; ForegroundColor = 'DarkCyan' ; BackgroundColor = 'Black' } +# DelimStatus1 = @{ PreText = '' ; ForegroundColor = 'Yellow' ; BackgroundColor = 'Black' } +# NumberStatus = @{ PreText = '#' ; ForegroundColor = 'DarkMagenta' ; BackgroundColor = 'Black' } +# DelimStatus2 = @{ PreText = ' ' ; ForegroundColor = 'Yellow' ; BackgroundColor = 'Black' } +# TitleStatus = @{ PreText = '' ; ForegroundColor = 'DarkGreen' ; BackgroundColor = 'Black' } +# SpaceStatus = @{ PreText = ' ' ; ForegroundColor = 'Black' ; BackgroundColor = 'Black' } +# OKStatus = @{ PreText = '≡' ; ForegroundColor = 'Green' ; BackgroundColor = 'Black' } +# KOStatus = @{ PreText = '!' ; ForegroundColor = 'White' ; BackgroundColor = 'Red' } +# AfterStatus = @{ PreText = ']' ; ForegroundColor = 'Yellow' ; BackgroundColor = 'Black' } +# NewlineStatus = @{ PreText = '`n' ; ForegroundColor = 'Black' ; BackgroundColor = 'Black' } +# +# Additional settings: +# HidePrompt ($false) - Set to $true to suppress the prompt entirely +# Verbose ($false) - Set to $true to enable verbose logging during render +# +# Dynamic values (from Get-ProjectHelperEnvironment): +# Owner - GitHub organization or user (shown by OwnerStatus) +# ProjectNumber - Project number (shown by NumberStatus, prefixed with '#') +# ProjectTitle - Project title (shown by TitleStatus) +# +# Staged-items indicator: +# When no items are staged → OKStatus is used (green '≡') +# When items are staged → KOStatus is used (red '!' followed by the count) +# +# To customize after initialization, retrieve and modify the settings: +# $s = Get-ProjecthelperPromptSettings +# $s.BeforeStatus.ForegroundColor = 'Cyan' +# $s.NumberStatus.PreText = 'No.' +# +# To re-initialize with defaults: +# Initialize-ProjectHelperPromptSettings -Force +# +# To show/hide the prompt at runtime: +# Show-ProjecthelperPrompt +# Hide-ProjecthelperPrompt +# #> Set-MyInvokeCommandAlias -Alias ProjectHelperPromptSettingsVariableName -Command "echo ProjecthelperPromoptSettings" From faf042a53350ce847430ed2ef2bf4669c113f24d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Sat, 28 Feb 2026 20:54:31 +0100 Subject: [PATCH 11/11] feat(project): add View parameter to Open-Project function for URL customization --- public/project/getproject.ps1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/public/project/getproject.ps1 b/public/project/getproject.ps1 index 5e57a7a..c287d2f 100644 --- a/public/project/getproject.ps1 +++ b/public/project/getproject.ps1 @@ -66,7 +66,8 @@ function Open-Project{ [CmdletBinding()] param( [Parameter(ValueFromPipelineByPropertyName)][string]$Owner, - [Parameter(ValueFromPipelineByPropertyName)][int]$ProjectNumber + [Parameter(ValueFromPipelineByPropertyName)][int]$ProjectNumber, + [Parameter(ValueFromPipelineByPropertyName)][string]$View ) ($Owner, $ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber @@ -75,7 +76,14 @@ function Open-Project{ if (-not $project) { throw "Project not found for Owner [$Owner] and ProjectNumber [$ProjectNumber]" } - $projectUrl = $project.url + + $builder = [UriBuilder]$project.url + + if (-Not [string]::IsNullOrEmpty($View)) { + $builder.Path = "$($builder.Path)/views/$View" + } + + $projectUrl = $builder.Uri # Open the URL based on the operating system if ($IsWindows -or $env:OS -match "Windows") {