From d446df6732d1640c72bb586d0e0de2b6800cc0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 21:21:28 +0100 Subject: [PATCH 1/9] feat(items): add project name validation for Get-GcProjectItems and Get-GcProject functions --- public/items/GcProjectItems.ps1 | 13 ++++++++++++- public/projects/GcProjects.ps1 | 31 +++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/public/items/GcProjectItems.ps1 b/public/items/GcProjectItems.ps1 index 32aa4a2..042cdd6 100644 --- a/public/items/GcProjectItems.ps1 +++ b/public/items/GcProjectItems.ps1 @@ -1,3 +1,6 @@ + +class ValidProjectNames : System.Management.Automation.IValidateSetValuesGenerator { [String[]] GetValidValues() { return GetValidProjectNames}} + function Get-GcProjectItems{ [CmdletBinding()] [Alias ("scpi")] @@ -13,17 +16,25 @@ function Get-GcProjectItems{ # [Parameter()][switch]$AnyField, # [Parameter()][switch]$Exact - [Parameter()][string]$RepositoryName + [Parameter()][string]$RepositoryName, + [Parameter()][ValidateSet([ValidProjectNames])][string]$ProjectName + ) $found = @((Get-AllItems -Force:$Force).Values) + # Owner and ProjectNumber filtering if(-Not [string]::IsNullOrEmpty($Owner)){ $found = @($found | Where-Object {$_.projectOwner -eq $Owner}) } + # ProjectName + if(-Not [string]::IsNullOrEmpty($ProjectName)){ + $projectnumber = (Get-GcProject -ProjectName $ProjectName).ProjectNumber + } + # ProjectNumber filtering if(-Not [string]::IsNullOrEmpty($ProjectNumber)){ if(-Not [string]::IsNullOrEmpty($ProjectNumber)){ $found = @($found | Where-Object {$_.projectNumber -eq $ProjectNumber}) diff --git a/public/projects/GcProjects.ps1 b/public/projects/GcProjects.ps1 index fb2ca58..6a861d6 100644 --- a/public/projects/GcProjects.ps1 +++ b/public/projects/GcProjects.ps1 @@ -1,12 +1,20 @@ Set-MyInvokeCommandAlias -Alias FindProjectByCreator -Command 'Find-Project -owner {owner} -pattern creator:{handle}' +class ValidProjectNames : System.Management.Automation.IValidateSetValuesGenerator { [String[]] GetValidValues() { return GetValidProjectNames}} +$script:projectlist = $null + function Get-GcProjects { [CmdletBinding()] param( - [parameter()][switch]$IncludeClosed + [parameter()][switch]$IncludeClosed, + [parameter()][switch]$Force ) + if(! $Force -and $null -ne $script:projectlist){ + return $script:projectlist + } + $me = Get-MyHandle $owner = 'githubcustomers' @@ -36,7 +44,26 @@ function Get-GcProjects { $ret.$name= $n } + + $script:projectlist = $ret return $ret -} Export-ModuleMember -Function Get-GcProjects \ No newline at end of file +} Export-ModuleMember -Function Get-GcProjects + +function Get-GcProject{ + [CmdletBinding()] + [Alias("gcp")] + param( + [Parameter(Mandatory,Position = 0)][ValidateSet([ValidProjectNames])][string]$ProjectName + ) + + $projects = Get-GcProjects + + return $projects.$ProjectName +} Export-ModuleMember -Function Get-GcProject -Alias gcp + +function GetValidProjectNames{ + $projects = Get-GcProjects + return $projects.keys +} \ No newline at end of file From 233c9e14d3314cbfba5d4872db5a09be73a98771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 21:42:15 +0100 Subject: [PATCH 2/9] fat(MyHandle): add cache to get-MyHangle --- include/MyHandle.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/MyHandle.ps1 b/include/MyHandle.ps1 index 88c7269..92fbc4b 100644 --- a/include/MyHandle.ps1 +++ b/include/MyHandle.ps1 @@ -1,10 +1,18 @@ Set-MyInvokeCommandAlias -Alias GetGhHandle -Command 'gh api user --jq ".login"' +$Script:myHandle = $null + function Get-MyHandle{ [CmdletBinding()] param() + + if($null -ne $Script:myHandle){ + return $Script:myHandle + } $user = Invoke-MyCommand -Command GetGhHandle + + $Script:myHandle = $user return $user } \ No newline at end of file From 979e6971ccade5aeef144ffb4ae0491571519b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 21:56:08 +0100 Subject: [PATCH 3/9] feat(repos): implement Get-GcRepos and related functions for repository retrieval --- public/getrepos.ps1 | 26 ---------- public/repos/getrepos.ps1 | 100 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 26 deletions(-) delete mode 100644 public/getrepos.ps1 create mode 100644 public/repos/getrepos.ps1 diff --git a/public/getrepos.ps1 b/public/getrepos.ps1 deleted file mode 100644 index 5f00e5c..0000000 --- a/public/getrepos.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -<# -.SYNOPSIS -Gets the GitHubCustomers repository owned by a particular SolutionEngineer -.DESCRIPTION -Gets the GitHubCustomers repository owned by a particular SolutionEngineer - -.PARAMETER Handle -The GitHub handle of the SolutionEngineer Custom Property value of the repository owner -#> -function Get-GcRepo { - param ( - [Parameter(Mandatory,Position=0)][string]$PropertyValue, - [Parameter()][string]$PropertyName = 'SolutionEngineer' - ) - $SearchString = "org:githubcustomers props.{property}:{value}" - - $SearchString = $SearchString -replace '{value}', $PropertyValue - $SearchString = $SearchString -replace '{property}', $PropertyName - - $SearchString | Write-Verbose - - $ret = Search-Repo -SearchString $SearchString - - return $ret - -} Export-ModuleMember -Function Get-GcRepo \ No newline at end of file diff --git a/public/repos/getrepos.ps1 b/public/repos/getrepos.ps1 new file mode 100644 index 0000000..4b11662 --- /dev/null +++ b/public/repos/getrepos.ps1 @@ -0,0 +1,100 @@ + +Set-MyInvokeCommandAlias -Alias SearchRepos -Command 'Invoke-SearchRepo -SearchString "{searchstring}"' + +class ValidRepoNames : System.Management.Automation.IValidateSetValuesGenerator { [String[]] GetValidValues() { return GetValidRepoNames}} + +$script:repoList = @{} + +function Get-GcReposMy{ + [CmdletBinding()] + param( + [Parameter()][switch]$Force + ) + + $handle = Get-MyHandle + + if($null -ne $script:repoList.$handle -and -not $Force){ + return $script:repoList.$handle + } + + $ret = Get-GcRepos -PropertyValue $handle -Force:$Force + + $script:repoList.$handle = $ret + + return $ret + +} Export-ModuleMember -Function Get-GcReposMy + +<# +.SYNOPSIS +Gets the GitHubCustomers repository owned by a particular SolutionEngineer +.DESCRIPTION +Gets the GitHubCustomers repository owned by a particular SolutionEngineer + +.PARAMETER Handle +The GitHub handle of the SolutionEngineer Custom Property value of the repository owner +#> +function Get-GcRepos { + param ( + [Parameter(Mandatory,Position=0)][string]$PropertyValue, + [Parameter()][string]$PropertyName = 'SolutionEngineer', + [Parameter()][switch]$Force + ) + + $SearchString = "org:githubcustomers props.{property}:{value}" + + $SearchString = $SearchString -replace '{value}', $PropertyValue + $SearchString = $SearchString -replace '{property}', $PropertyName + + $SearchString | Write-Verbose + + $response = Invoke-MyCommand -Command SearchRepos -Parameters @{searchstring=$SearchString} + + $ret = @{} + foreach($r in $response){ + $n = [pscustomobject]@{ + name = $r.name + url = $r.url + } + $ret.$($r.name) = $n + } + + return $ret + +} Export-ModuleMember -Function Get-GcRepos + +function Get-GcRepo{ + [CmdletBinding()] + param( + [Parameter(Mandatory,Position=0)][ValidateSet([ValidRepoNames])][string]$RepositoryName + ) + + $repos = Get-GcReposMy + return $repos.$RepositoryName +} Export-ModuleMember -Function Get-GcRepo + +function Invoke-SearchRepo{ + [CmdletBinding()] + param( + [Parameter(Mandatory,Position=0)][string]$SearchString + ) + + $attributes = 'name,url' + + $command = 'gh search repos {searchstring} --json {attributes}' + + $command = $command -replace "{searchstring}", "$($SearchString)" + $command = $command -replace "{attributes}", "$($attributes)" + + $command | Write-Verbose + + $ret = Invoke-Expression $Command | ConvertFrom-Json + + return $ret +} Export-ModuleMember -Function Invoke-SearchRepo + +function GetValidRepoNames{ + + $repos = Get-GcReposMy + return $repos.keys +} \ No newline at end of file From f6a7af39e7b8bed8f88a88eda071295de9bf038c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 22:07:42 +0100 Subject: [PATCH 4/9] feat(tests): add Invoke-PrivateContext function for invoking private module functions --- Test/include/callPrivateContext.ps1 | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Test/include/callPrivateContext.ps1 diff --git a/Test/include/callPrivateContext.ps1 b/Test/include/callPrivateContext.ps1 new file mode 100644 index 0000000..d4aabd9 --- /dev/null +++ b/Test/include/callPrivateContext.ps1 @@ -0,0 +1,39 @@ +# CALL PRIVATE FUNCTIONS +# +# This file enables tests to invoke private (non-exported) functions +# defined inside the main module by evaluating a provided scriptblock +# in the module context. +# +# It relies on variables initialized by module.helper.ps1. +# REQUIRED: +# $MODULE_PATH - Full path to the module .psm1 file (or a file inside its folder) +# +# THIS INCLUDE REQUIRES module.helper.ps1 +if(-not $MODULE_PATH){ throw "Missing MODULE_PATH variable initialization. Check for module.helper.ps1 file." } + +function Invoke-PrivateContext { + param ( + [Parameter(Mandatory, Position = 0)] + [scriptblock]$ScriptBlock, + [string]$ModulePath, + [string[]]$Arguments + ) + + if ([string]::IsNullOrEmpty($ModulePath)) { + $modulePath = $MODULE_PATH | Split-Path -Parent + } + + $module = Import-Module -Name $modulePath -PassThru + + if ($null -eq $module) { + throw "Failed to import the main module." + } + + if($Arguments){ + & $module $ScriptBlock -Arguments $Arguments + } + else { + & $module $ScriptBlock + } + +} Export-ModuleMember -Function Invoke-PrivateContext From aa2f8de3ef8749581c56a3a04978db43fbc8e903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 22:07:55 +0100 Subject: [PATCH 5/9] feat(items): add validation for RepositoryName parameter in Get-GcProjectItems --- public/items/GcProjectItems.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/items/GcProjectItems.ps1 b/public/items/GcProjectItems.ps1 index 042cdd6..8b59fdd 100644 --- a/public/items/GcProjectItems.ps1 +++ b/public/items/GcProjectItems.ps1 @@ -1,5 +1,7 @@ class ValidProjectNames : System.Management.Automation.IValidateSetValuesGenerator { [String[]] GetValidValues() { return GetValidProjectNames}} +class ValidRepoNames : System.Management.Automation.IValidateSetValuesGenerator { [String[]] GetValidValues() { return GetValidRepoNames}} + function Get-GcProjectItems{ [CmdletBinding()] @@ -16,10 +18,8 @@ function Get-GcProjectItems{ # [Parameter()][switch]$AnyField, # [Parameter()][switch]$Exact - [Parameter()][string]$RepositoryName, + [Parameter()][ValidateSet([ValidRepoNames])][string]$RepositoryName, [Parameter()][ValidateSet([ValidProjectNames])][string]$ProjectName - - ) $found = @((Get-AllItems -Force:$Force).Values) From 6e5fbb3da92710d8835b9741991feaddf64ceafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 22:08:03 +0100 Subject: [PATCH 6/9] refactor(tests): clear repo list cache in Run_BeforeEach function --- Test/private/run_BeforeAfter.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Test/private/run_BeforeAfter.ps1 b/Test/private/run_BeforeAfter.ps1 index 2ed9bfe..c4536e5 100644 --- a/Test/private/run_BeforeAfter.ps1 +++ b/Test/private/run_BeforeAfter.ps1 @@ -19,7 +19,12 @@ function Run_BeforeEach{ # Write-Verbose "Run_BeforeEach" Reset-InvokeCommandMock - + + Invoke-PrivateContext { + # Clear the repo list cache to ensure tests are isolated + $script:projectlist = $null + $script:repoList = @{} + } } # function Run_AfterEach{ From 3914beb31e1d87c6508fa44da7cf75b2c388f5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 22:08:14 +0100 Subject: [PATCH 7/9] test(GcProjects): add tests for Get-GcProjects function --- Test/public/items/GcProjects.test.ps1 | 18 ------- Test/public/projects/GcProjects.test.ps1 | 62 ++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 18 deletions(-) delete mode 100644 Test/public/items/GcProjects.test.ps1 create mode 100644 Test/public/projects/GcProjects.test.ps1 diff --git a/Test/public/items/GcProjects.test.ps1 b/Test/public/items/GcProjects.test.ps1 deleted file mode 100644 index 6af8728..0000000 --- a/Test/public/items/GcProjects.test.ps1 +++ /dev/null @@ -1,18 +0,0 @@ -function Test_GetGcProjects { - - MockCallToString -Command 'gh api user --jq ".login"' -OutString 'testuser' - - MockCallJson -Command "Find-Project -owner githubcustomers -pattern creator:testuser" -filename "testuser-find-project.json" - - $projects = Get-GcProjects - - Assert-Count -Expected 16 -Presented $projects - - # Pick one random and check the structure - $testProject = $projects."bit21" - Assert-AreEqual -Expected "bit21" -Presented $testProject.Title - Assert-AreEqual -Expected "githubcustomers" -Presented $testProject.Owner - Assert-AreEqual -Expected 2683 -Presented $testProject.ProjectNumber - Assert-AreEqual -Expected "https://github.com/orgs/githubcustomers/projects/2683" -Presented $testProject.Url - -} \ No newline at end of file diff --git a/Test/public/projects/GcProjects.test.ps1 b/Test/public/projects/GcProjects.test.ps1 new file mode 100644 index 0000000..d98823a --- /dev/null +++ b/Test/public/projects/GcProjects.test.ps1 @@ -0,0 +1,62 @@ +function Test_GetGcProjects { + + MockCallToString -Command 'gh api user --jq ".login"' -OutString 'testuser' + + MockCallJson -Command "Find-Project -owner githubcustomers -pattern creator:testuser" -filename "testuser-find-project.json" + + $projects = Get-GcProjects + + Assert-Count -Expected 16 -Presented $projects + + # Pick one random and check the structure + $testProject = $projects."bit21" + Assert-AreEqual -Expected "bit21" -Presented $testProject.Title + Assert-AreEqual -Expected "githubcustomers" -Presented $testProject.Owner + Assert-AreEqual -Expected 2683 -Presented $testProject.ProjectNumber + Assert-AreEqual -Expected "https://github.com/orgs/githubcustomers/projects/2683" -Presented $testProject.Url + +} + +function Test_GetGcProjects_Success{ + + # Arrange + MockCall_GetGcProjects + + # Act + $result = Get-GcProjects + + # Assert + Assert-Count -Expected 3 -Presented $result.Keys + Assert-Contains -Presented $result.Keys -Expected "Customer_1" + Assert-Contains -Presented $result.Keys -Expected "_TEMPLATE__Customer_Project" + Assert-Contains -Presented $result.Keys -Expected "BiT21" + + # Verify structure of one project + Assert-AreEqual -Expected "BiT21" -Presented $result.BiT21.Title + Assert-AreEqual -Expected "githubcustomers" -Presented $result.BiT21.Owner + Assert-AreEqual -Expected 2683 -Presented $result.BiT21.ProjectNumber + Assert-AreEqual -Expected "https://github.com/orgs/githubcustomers/projects/2683" -Presented $result.BiT21.Url +} + +function Test_GetGcProjects_WithForce{ + + # Arrange + MockCall_GetGcProjects + + # Act - First call + $result1 = Get-GcProjects + # Act - Second call without Force (should use cache) + $result2 = Get-GcProjects + # Act - Third call with Force (should refresh) + $result3 = Get-GcProjects -Force + + # Assert + Assert-Count -Expected 3 -Presented $result1.Keys + Assert-Count -Expected 3 -Presented $result2.Keys + Assert-Count -Expected 3 -Presented $result3.Keys +} + +function MockCall_GetGcProjects{ + MockCallToString -Command 'gh api user --jq ".login"' -OutString 'testuser' + MockCallJson -Command "Find-Project -owner githubcustomers -pattern creator:testuser" -filename "testuser-find-project-3.json" +} From 634da8b8cc16b6fa3216bc258430d561cdce764e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 22:35:55 +0100 Subject: [PATCH 8/9] test(GcProjectItems): add mock call for GetGcReposMy in project items tests --- Test/public/items/GcProjectItems.test.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Test/public/items/GcProjectItems.test.ps1 b/Test/public/items/GcProjectItems.test.ps1 index 404ca34..ce12a07 100644 --- a/Test/public/items/GcProjectItems.test.ps1 +++ b/Test/public/items/GcProjectItems.test.ps1 @@ -1,6 +1,7 @@ function Test_GetProjectItems_Success{ MockCall_GetAllItems + MockCall_GetGcReposMy # All # Act @@ -52,7 +53,10 @@ function GetMockFiles($ProjectNumber){ function MockCall_GetAllItems{ + # GetMyHandle MockCallToString -Command 'gh api user --jq ".login"' -OutString 'testuser' + + # Get-AllItems MockCallJson -Command "Find-Project -owner githubcustomers -pattern creator:testuser" -filename "testuser-find-project-3.json" MockCall_GetProject 2683 ; MockCall_GetProject 2988 ; MockCall_GetProject 3023 From 0707c69b147d6101e77788615331b23c51f9bba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20=28Dibildos=29=20Gonz=C3=A1lez?= Date: Mon, 9 Mar 2026 22:36:01 +0100 Subject: [PATCH 9/9] test(repos): add tests for Get-GcReposMy and Get-GcRepos functions --- Test/mockfiles.log | 4 + Test/private/mocks/testuser-search-repos.json | 90 +++++++++++++++++++ Test/private/run_BeforeAfter.ps1 | 2 +- Test/public/repos/getrepos.test.ps1 | 61 +++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 Test/private/mocks/testuser-search-repos.json create mode 100644 Test/public/repos/getrepos.test.ps1 diff --git a/Test/mockfiles.log b/Test/mockfiles.log index b5b3399..0b59a4e 100644 --- a/Test/mockfiles.log +++ b/Test/mockfiles.log @@ -26,5 +26,9 @@ { "Command": "Get-ProjectItems -owner githubcustomers -projectNumber 3023 -IncludeDone", "FileName": "get-projectitems-githubcustomers-3023.json" + }, + { + "FileName": "testuser-search-repos.json", + "Command": "Invoke-SearchRepo -SearchString \"org:githubcustomers props.SolutionEngineer:testuser\"" } ] diff --git a/Test/private/mocks/testuser-search-repos.json b/Test/private/mocks/testuser-search-repos.json new file mode 100644 index 0000000..ffc7996 --- /dev/null +++ b/Test/private/mocks/testuser-search-repos.json @@ -0,0 +1,90 @@ +[ + { + "name": "Santander", + "url": "https://github.com/githubcustomers/Santander" + }, + { + "name": "santander-cybersecurity", + "url": "https://github.com/githubcustomers/santander-cybersecurity" + }, + { + "name": "ECI", + "url": "https://github.com/githubcustomers/ECI" + }, + { + "name": "iberdrola", + "url": "https://github.com/githubcustomers/iberdrola" + }, + { + "name": "indra-mobility", + "url": "https://github.com/githubcustomers/indra-mobility" + }, + { + "name": "adevinta-motor", + "url": "https://github.com/githubcustomers/adevinta-motor" + }, + { + "name": "bit21", + "url": "https://github.com/githubcustomers/bit21" + }, + { + "name": "santander-internal", + "url": "https://github.com/githubcustomers/santander-internal" + }, + { + "name": "bbva-global-security", + "url": "https://github.com/githubcustomers/bbva-global-security" + }, + { + "name": "indra", + "url": "https://github.com/githubcustomers/indra" + }, + { + "name": "bbva-internal", + "url": "https://github.com/githubcustomers/bbva-internal" + }, + { + "name": "mapfre", + "url": "https://github.com/githubcustomers/mapfre" + }, + { + "name": "microsoft-spain-internal", + "url": "https://github.com/githubcustomers/microsoft-spain-internal" + }, + { + "name": "inditex", + "url": "https://github.com/githubcustomers/inditex" + }, + { + "name": "indra-group", + "url": "https://github.com/githubcustomers/indra-group" + }, + { + "name": "sw-se-team", + "url": "https://github.com/githubcustomers/sw-se-team" + }, + { + "name": "bbva-accenture", + "url": "https://github.com/githubcustomers/bbva-accenture" + }, + { + "name": "bbva", + "url": "https://github.com/githubcustomers/bbva" + }, + { + "name": "santander-global-tech", + "url": "https://github.com/githubcustomers/santander-global-tech" + }, + { + "name": "kk", + "url": "https://github.com/githubcustomers/kk" + }, + { + "name": "caixabank", + "url": "https://github.com/githubcustomers/caixabank" + }, + { + "name": "EPO", + "url": "https://github.com/githubcustomers/EPO" + } +] diff --git a/Test/private/run_BeforeAfter.ps1 b/Test/private/run_BeforeAfter.ps1 index c4536e5..c36700a 100644 --- a/Test/private/run_BeforeAfter.ps1 +++ b/Test/private/run_BeforeAfter.ps1 @@ -22,7 +22,7 @@ function Run_BeforeEach{ Invoke-PrivateContext { # Clear the repo list cache to ensure tests are isolated - $script:projectlist = $null + $script:projectlist = $null $script:repoList = @{} } } diff --git a/Test/public/repos/getrepos.test.ps1 b/Test/public/repos/getrepos.test.ps1 new file mode 100644 index 0000000..9296e68 --- /dev/null +++ b/Test/public/repos/getrepos.test.ps1 @@ -0,0 +1,61 @@ +function Test_GetGcReposMy_Success{ + + # Arrange + MockCall_GetGcReposMy + + # Act + $result = Get-GcReposMy + + # Assert + Assert-Count -Expected 22 -Presented $result.Keys + Assert-Contains -Presented $result.Keys -Expected "kk" + Assert-Contains -Presented $result.Keys -Expected "bit21" + + # Verify structure of one repo + Assert-AreEqual -Expected "bit21" -Presented $result.bit21.name + Assert-AreEqual -Expected "https://github.com/githubcustomers/bit21" -Presented $result.bit21.url +} + +function Test_GetGcReposMy_WithForce{ + + # Arrange + MockCall_GetGcReposMy + + # Act - First call + $result1 = Get-GcReposMy + # Act - Second call without Force (should use cache) + $result2 = Get-GcReposMy + # Act - Third call with Force (should refresh) + $result3 = Get-GcReposMy -Force + + # Assert + Assert-Count -Expected 22 -Presented $result1.Keys + Assert-Count -Expected 22 -Presented $result2.Keys + Assert-Count -Expected 22 -Presented $result3.Keys +} + +function Test_GetGcRepos_Success{ + + # Arrange + MockCall_SearchRepos + + # Act + $result = Get-GcRepos -PropertyValue "testuser" + + # Assert + Assert-Count -Expected 22 -Presented $result.Keys + Assert-Contains -Presented $result.Keys -Expected "kk" + Assert-Contains -Presented $result.Keys -Expected "bit21" +} + +function MockCall_GetGcReposMy{ + # GetMyHandle + MockCallToString -Command 'gh api user --jq ".login"' -OutString 'testuser' + + # SearchRepos + MockCall_SearchRepos +} + +function MockCall_SearchRepos{ + MockCallJson -Command 'Invoke-SearchRepo -SearchString "org:githubcustomers props.SolutionEngineer:testuser"' -filename "testuser-search-repos.json" +}