From a2e49c237703d6f8de23bd5806083a432911bda3 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 1 Jul 2025 11:00:47 +0200 Subject: [PATCH 01/27] =?UTF-8?q?=F0=9F=9A=80[Feature]:=20Add=20functions?= =?UTF-8?q?=20to=20revoke=20tokens=20+=20remove=20some=20functions=20(#432?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces new functionality for revoking GitHub access tokens, enhances the `Disconnect-GitHubAccount` command to revoke tokens, and refactors or removes outdated examples and tests. These changes improve security and streamline token management. - Fixes #414 ### Hiding some functions that were public previously - New-GitHubAppInstallationAccessToken - Get-GitHubAppJSONWebToken ### New Features for Token Revocation * Added `Revoke-GitHubAppInstallationAccessToken` (private) function to revoke installation access tokens for GitHub Apps. This invalidates tokens and ensures they cannot be reused. * Introduced `Revoke-GitHubAccessToken` (public) function to revoke a list of exposed or unused credentials. Supports batch processing for up to 1000 tokens per request. ### Enhancements to Existing Commands * Updated `Disconnect-GitHubAccount` to revoke access tokens during disconnection, improving security by preventing token reuse for Installation Access Tokens. ### Refactoring and Cleanup * Removed outdated examples from `CallingAPIs.ps1` related to JWT and installation access tokens. * Refactored tests in `Apps.Tests.ps1` by removing redundant JWT and installation token tests, and added a test to verify that revoked tokens fail API calls. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug --- examples/CallingAPIs.ps1 | 6 -- .../Get-GitHubAppJSONWebToken.ps1 | 0 .../New-GitHubAppInstallationAccessToken.ps1 | 0 ...evoke-GitHubAppInstallationAccessToken.ps1 | 46 +++++++++ .../public/Auth/Disconnect-GitHubAccount.ps1 | 20 +++- .../public/Auth/Revoke-GitHubAccessToken.ps1 | 53 +++++++++++ tests/Apps.Tests.ps1 | 95 +++++++++---------- 7 files changed, 164 insertions(+), 56 deletions(-) rename src/functions/{public/Apps/GitHub App => private/Apps/GitHub Apps}/Get-GitHubAppJSONWebToken.ps1 (100%) rename src/functions/{public/Apps/GitHub App => private/Apps/GitHub Apps}/New-GitHubAppInstallationAccessToken.ps1 (100%) create mode 100644 src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 create mode 100644 src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 diff --git a/examples/CallingAPIs.ps1 b/examples/CallingAPIs.ps1 index e8c70c1a2..578f72bf8 100644 --- a/examples/CallingAPIs.ps1 +++ b/examples/CallingAPIs.ps1 @@ -26,12 +26,6 @@ Get-GitHubApp # More complex example - output is parts of the web response Invoke-GitHubAPI -ApiEndpoint /app -# Most complex example - output is the entire web response -$context = Get-GitHubContext -$jwt = Get-GitHubAppJSONWebToken -ClientId $context.ClientID -PrivateKey $context.Token -Invoke-RestMethod -Uri "$($context.ApiBaseUri)/app" -Token ($jwt.token) -Authentication Bearer -Invoke-WebRequest -Uri "$($context.ApiBaseUri)/app" -Token ($jwt.token) -Authentication Bearer - #endregion diff --git a/src/functions/public/Apps/GitHub App/Get-GitHubAppJSONWebToken.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 similarity index 100% rename from src/functions/public/Apps/GitHub App/Get-GitHubAppJSONWebToken.ps1 rename to src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 diff --git a/src/functions/public/Apps/GitHub App/New-GitHubAppInstallationAccessToken.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 similarity index 100% rename from src/functions/public/Apps/GitHub App/New-GitHubAppInstallationAccessToken.ps1 rename to src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 diff --git a/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 b/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 new file mode 100644 index 000000000..99a5cf3b1 --- /dev/null +++ b/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 @@ -0,0 +1,46 @@ +function Revoke-GitHubAppInstallationAccessToken { + <# + .SYNOPSIS + Revoke an installation access token. + + .DESCRIPTION + Revokes the installation token you're using to authenticate as an installation and access this endpoint. + Once an installation token is revoked, the token is invalidated and cannot be used. Other endpoints that require the revoked installation + token must have a new installation token to work. You can create a new token using the `Connect-GitHubApp` function. + + .LINK + https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Revoke-GitHubAppInstallationAccessToken + + .NOTES + [Revoke an installation access token](https://docs.github.com/rest/apps/installations#revoke-an-installation-access-token) + #> + [CmdletBinding(SupportsShouldProcess)] + param( + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT + } + + process { + $InputObject = @{ + Method = 'DELETE' + APIEndpoint = '/installation/token' + Context = $Context + } + + if ($PSCmdlet.ShouldProcess('GitHub App installation access token', 'Revoke')) { + Invoke-GitHubAPI @InputObject + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 b/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 index c7825b96f..9a3878c56 100644 --- a/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 @@ -4,7 +4,8 @@ Disconnects from GitHub and removes the GitHub context. .DESCRIPTION - Disconnects from GitHub and removes the GitHub context. + Disconnects from GitHub and removes the GitHub context. Optionally revokes the access token + to ensure it cannot be used after disconnection. .EXAMPLE Disconnect-GitHubAccount @@ -16,6 +17,16 @@ Disconnects from GitHub and removes the context 'github.com/Octocat'. + .EXAMPLE + Disconnect-GitHubAccount -RevokeToken + + Disconnects from GitHub, revokes the access token, and removes the default GitHub context. + + .EXAMPLE + Disconnect-GithubAccount -Context 'github.com/Octocat' -RevokeToken + + Disconnects from GitHub, revokes the access token, and removes the context 'github.com/Octocat'. + .LINK https://psmodule.io/GitHub/Functions/Auth/Disconnect-GitHubAccount #> @@ -46,6 +57,13 @@ } foreach ($contextItem in $Context) { $contextItem = Resolve-GitHubContext -Context $contextItem + + $contextToken = Get-GitHubAccessToken -Context $contextItem -AsPlainText + $isGitHubToken = $contextToken -eq (Get-GitHubToken | ConvertFrom-SecureString -AsPlainText) + if (-not $isGitHubToken -and $contextItem.AuthType -eq 'IAT') { + Revoke-GitHubAppInstallationAccessToken -Context $contextItem + } + Remove-GitHubContext -Context $contextItem $isDefaultContext = $contextItem.Name -eq $script:GitHub.Config.DefaultContext if ($isDefaultContext) { diff --git a/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 b/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 new file mode 100644 index 000000000..bfddcee90 --- /dev/null +++ b/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 @@ -0,0 +1,53 @@ +function Revoke-GitHubAccessToken { + <# + .SYNOPSIS + Revoke a list of tokens. + + .DESCRIPTION + Submit a list of credentials to be revoked. This endpoint is intended to revoke credentials the caller does not own and may have found + exposed on GitHub.com or elsewhere. It can also be used for credentials associated with an old user account that you no longer have access to. + Credential owners will be notified of the revocation. + + .LINK + https://psmodule.io/GitHub/Functions/Auth/Revoke-GitHubAccessToken/ + + .NOTES + [Revoke a list of credentials](https://docs.github.com/rest/credentials/revoke#revoke-a-list-of-credentials) + #> + [CmdletBinding(SupportsShouldProcess)] + param( + # An array of tokens to revoke. + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [string[]] $Token + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $tokenList = [System.Collections.ArrayList]::new() + } + + process { + $Token | ForEach-Object { + $tokenList.Add($_) + } + } + + end { + for ($i = 0; $i -lt $tokenList.Count; $i += 1000) { + $batch = $tokenList[$i..([Math]::Min($i + 999, $tokenList.Count - 1))] + $body = @{ credentials = $batch } + $InputObject = @{ + Method = 'POST' + APIEndpoint = '/credentials/revoke' + Body = $body + Anonymous = $true + } + if ($PSCmdlet.ShouldProcess('Tokens', 'Revoke')) { + Invoke-GitHubAPI @InputObject + } + } + Write-Debug "[$stackPath] - End" + } +} +#SkipTest:FunctionTest:Will add a test for this function in a future PR diff --git a/tests/Apps.Tests.ps1 b/tests/Apps.Tests.ps1 index e6613bb13..9ab74a455 100644 --- a/tests/Apps.Tests.ps1 +++ b/tests/Apps.Tests.ps1 @@ -61,14 +61,6 @@ Describe 'Apps' { $app.Installations | Should -Not -BeNullOrEmpty } - It 'Get-GitHubAppJSONWebToken - Can get a JWT for the app' { - $jwt = Get-GitHubAppJSONWebToken @connectParams - LogGroup 'JWT' { - Write-Host ($jwt | Format-Table | Out-String) - } - $jwt | Should -Not -BeNullOrEmpty - } - It 'Get-GitHubAppInstallationRequest - Can get installation requests' { $installationRequests = Get-GitHubAppInstallationRequest LogGroup 'Installation requests' { @@ -104,17 +96,6 @@ Describe 'Apps' { } } - It 'New-GitHubAppInstallationAccessToken - Can get app installation access tokens' { - $installations = Get-GitHubAppInstallation - LogGroup 'Tokens' { - $installations | ForEach-Object { - $token = New-GitHubAppInstallationAccessToken -InstallationID $_.id - Write-Host ($token | Format-List | Out-String) - } - $token | Should -Not -BeNullOrEmpty - } - } - It 'Get-GitHubAppInstallation - ' { $githubApp = Get-GitHubApp $installation = Get-GitHubAppInstallation | Where-Object { ($_.Target.Name -eq $owner) -and ($_.Type -eq $ownerType) } @@ -183,37 +164,53 @@ Describe 'Apps' { } } } - It 'Connect-GitHubApp - Connects as a GitHub App to ' { - $githubApp = Get-GitHubApp - $config = Get-GitHubConfig - $context = Connect-GitHubApp @connectAppParams -PassThru -Silent - LogGroup 'Context' { - Write-Host ($context | Format-List | Out-String) + + Context 'Installation' { + BeforeAll { + $githubApp = Get-GitHubApp + $config = Get-GitHubConfig + $context = Connect-GitHubApp @connectAppParams -PassThru -Silent + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + } + + It 'Connect-GitHubApp - Connects as a GitHub App to ' { + $context | Should -BeOfType 'InstallationGitHubContext' + $context.ClientID | Should -Be $githubApp.ClientID + $context.TokenExpirationDate | Should -BeOfType [datetime] + $context.InstallationID | Should -BeOfType [uint64] + $context.InstallationID | Should -BeGreaterThan 0 + $context.Permissions | Should -BeOfType [PSCustomObject] + $context.Events | Should -BeOfType 'string' + $context.InstallationType | Should -Be $ownertype + $context.InstallationName | Should -Be $owner + $context.ID | Should -Be "$($config.HostName)/$($githubApp.Slug)/$ownertype/$owner" + $context.Name | Should -Be "$($config.HostName)/$($githubApp.Slug)/$ownertype/$owner" + $context.DisplayName | Should -Be $githubApp.Name + $context.Type | Should -Be 'Installation' + $context.HostName | Should -Be $config.HostName + $context.ApiBaseUri | Should -Be $config.ApiBaseUri + $context.ApiVersion | Should -Be $config.ApiVersion + $context.AuthType | Should -Be 'IAT' + $context.NodeID | Should -Not -BeNullOrEmpty + $context.DatabaseID | Should -Not -BeNullOrEmpty + $context.UserName | Should -Be $githubApp.Slug + $context.Token | Should -BeOfType [System.Security.SecureString] + $context.TokenType | Should -Be 'ghs' + $context.HttpVersion | Should -Be $config.HttpVersion + $context.PerPage | Should -Be $config.PerPage + } + + It 'Revoked GitHub App token should fail on API call' -Skip:($TokenType -eq 'GITHUB_TOKEN') { + $org = Get-GitHubOrganization -Name PSModule -Context $context + $org | Should -Not -BeNullOrEmpty + $context | Disconnect-GitHub + + { + Invoke-RestMethod -Method Get -Uri "$($context.ApiBaseUri)/orgs/PSModule" -Authentication Bearer -Token $context.token + } | Should -Throw } - $context | Should -BeOfType 'InstallationGitHubContext' - $context.ClientID | Should -Be $githubApp.ClientID - $context.TokenExpirationDate | Should -BeOfType [datetime] - $context.InstallationID | Should -BeOfType [uint64] - $context.InstallationID | Should -BeGreaterThan 0 - $context.Permissions | Should -BeOfType [PSCustomObject] - $context.Events | Should -BeOfType 'string' - $context.InstallationType | Should -Be $ownertype - $context.InstallationName | Should -Be $owner - $context.ID | Should -Be "$($config.HostName)/$($githubApp.Slug)/$ownertype/$owner" - $context.Name | Should -Be "$($config.HostName)/$($githubApp.Slug)/$ownertype/$owner" - $context.DisplayName | Should -Be $githubApp.Name - $context.Type | Should -Be 'Installation' - $context.HostName | Should -Be $config.HostName - $context.ApiBaseUri | Should -Be $config.ApiBaseUri - $context.ApiVersion | Should -Be $config.ApiVersion - $context.AuthType | Should -Be 'IAT' - $context.NodeID | Should -Not -BeNullOrEmpty - $context.DatabaseID | Should -Not -BeNullOrEmpty - $context.UserName | Should -Be $githubApp.Slug - $context.Token | Should -BeOfType [System.Security.SecureString] - $context.TokenType | Should -Be 'ghs' - $context.HttpVersion | Should -Be $config.HttpVersion - $context.PerPage | Should -Be $config.PerPage } } From 1b4773a55f306957a72634b148da8f25b2c6c1e9 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Tue, 1 Jul 2025 20:05:02 +0200 Subject: [PATCH 02/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20a=20dynam?= =?UTF-8?q?ically=20format=20property=20for=20`GitHubContext`=20(#449)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces a new `Remaining` property to GitHub context types and updates the display format to show the time remaining until token expiration. The changes improve the clarity and usability of token expiration information by providing both textual and color-coded visual indicators. ### Enhancements to GitHub context display: * **Added a new column for `Remaining` in the table display**: - Updated `src/formats/GitHubContext.Format.ps1xml` to include a `Remaining` column header and display logic for the time remaining until token expiration. The display uses a color-coded system based on the ratio of remaining time to the maximum allowed duration, enhancing visual clarity. [[1]](diffhunk://#diff-c7dd80cd4c4440ccbe24930842a2e172614dbfd79d31393d68852200eacc2c74R29-R31) [[2]](diffhunk://#diff-c7dd80cd4c4440ccbe24930842a2e172614dbfd79d31393d68852200eacc2c74R55-R97) ### GitHub context types improvements: * **Introduced the `Remaining` property for token expiration**: - Added a `Remaining` script property to both `InstallationGitHubContext` and `UserGitHubContext` types in `src/types/GitHubContext.Types.ps1xml`. This property calculates the time span between the current date and the token expiration date, enabling the new display functionality. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- src/classes/public/Context/GitHubContext.ps1 | 22 ++++++++- .../GitHubContext/AppGitHubContext.ps1 | 37 +++++++++----- .../InstallationGitHubContext.ps1 | 43 +++++++++++------ .../GitHubContext/UserGitHubContext.ps1 | 40 ++++++++++------ src/formats/GitHubContext.Format.ps1xml | 48 +++++++++++++++++++ .../Auth/Context/Resolve-GitHubContext.ps1 | 10 ++-- .../public/Auth/Context/Get-GitHubContext.ps1 | 6 +-- src/types/GitHubContext.Types.ps1xml | 27 +++++++++++ 8 files changed, 183 insertions(+), 50 deletions(-) create mode 100644 src/types/GitHubContext.Types.ps1xml diff --git a/src/classes/public/Context/GitHubContext.ps1 b/src/classes/public/Context/GitHubContext.ps1 index 8145217cd..4eaee6d32 100644 --- a/src/classes/public/Context/GitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext.ps1 @@ -62,9 +62,29 @@ # The default value for the 'per_page' API parameter used in 'GET' functions that support paging. [int] $PerPage - # Simple parameterless constructor GitHubContext() {} + GitHubContext([pscustomobject]$Object) { + $this.ID = $Object.ID + $this.Name = $Object.Name + $this.DisplayName = $Object.DisplayName + $this.Type = $Object.Type + $this.HostName = $Object.HostName + $this.ApiBaseUri = $Object.ApiBaseUri + $this.ApiVersion = $Object.ApiVersion + $this.AuthType = $Object.AuthType + $this.NodeID = $Object.NodeID + $this.DatabaseID = $Object.DatabaseID + $this.UserName = $Object.UserName + $this.Token = $Object.Token + $this.TokenType = $Object.TokenType + $this.Enterprise = $Object.Enterprise + $this.Owner = $Object.Owner + $this.Repository = $Object.Repository + $this.HttpVersion = $Object.HttpVersion + $this.PerPage = $Object.PerPage + } + [string] ToString() { return $this.Name } diff --git a/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 index 68a010afd..e9e795adf 100644 --- a/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 @@ -14,20 +14,31 @@ # The events that the app is subscribing to once installed [string[]] $Events - # Simple parameterless constructor AppGitHubContext() {} - # Creates a context object from a hashtable of key-vaule pairs. - AppGitHubContext([hashtable]$Properties) { - foreach ($Property in $Properties.Keys) { - $this.$Property = $Properties.$Property - } - } - - # Creates a context object from a PSCustomObject. - AppGitHubContext([PSCustomObject]$Object) { - $Object.PSObject.Properties | ForEach-Object { - $this.($_.Name) = $_.Value - } + AppGitHubContext([pscustomobject]$Object) { + $this.ID = $Object.ID + $this.Name = $Object.Name + $this.DisplayName = $Object.DisplayName + $this.Type = $Object.Type + $this.HostName = $Object.HostName + $this.ApiBaseUri = $Object.ApiBaseUri + $this.ApiVersion = $Object.ApiVersion + $this.AuthType = $Object.AuthType + $this.NodeID = $Object.NodeID + $this.DatabaseID = $Object.DatabaseID + $this.UserName = $Object.UserName + $this.Token = $Object.Token + $this.TokenType = $Object.TokenType + $this.Enterprise = $Object.Enterprise + $this.Owner = $Object.Owner + $this.Repository = $Object.Repository + $this.HttpVersion = $Object.HttpVersion + $this.PerPage = $Object.PerPage + $this.ClientID = $Object.ClientID + $this.OwnerName = $Object.OwnerName + $this.OwnerType = $Object.OwnerType + $this.Permissions = $Object.Permissions + $this.Events = $Object.Events } } diff --git a/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 index b7dc45a15..c1a6ec77a 100644 --- a/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 @@ -4,10 +4,10 @@ # The token expiration date. # 2024-01-01-00:00:00 - [datetime] $TokenExpirationDate + [System.Nullable[datetime]] $TokenExpirationDate # The installation ID. - [uint64] $InstallationID + [System.Nullable[uint64]] $InstallationID # The permissions that the app is requesting on the target [pscustomobject] $Permissions @@ -21,20 +21,33 @@ # The target login or slug of the installation. [string] $InstallationName - # Simple parameterless constructor InstallationGitHubContext() {} - # Creates a context object from a hashtable of key-vaule pairs. - InstallationGitHubContext([hashtable]$Properties) { - foreach ($Property in $Properties.Keys) { - $this.$Property = $Properties.$Property - } - } - - # Creates a context object from a PSCustomObject. - InstallationGitHubContext([PSCustomObject]$Object) { - $Object.PSObject.Properties | ForEach-Object { - $this.($_.Name) = $_.Value - } + InstallationGitHubContext([pscustomobject]$Object) { + $this.ID = $Object.ID + $this.Name = $Object.Name + $this.DisplayName = $Object.DisplayName + $this.Type = $Object.Type + $this.HostName = $Object.HostName + $this.ApiBaseUri = $Object.ApiBaseUri + $this.ApiVersion = $Object.ApiVersion + $this.AuthType = $Object.AuthType + $this.NodeID = $Object.NodeID + $this.DatabaseID = $Object.DatabaseID + $this.UserName = $Object.UserName + $this.Token = $Object.Token + $this.TokenType = $Object.TokenType + $this.Enterprise = $Object.Enterprise + $this.Owner = $Object.Owner + $this.Repository = $Object.Repository + $this.HttpVersion = $Object.HttpVersion + $this.PerPage = $Object.PerPage + $this.ClientID = $Object.ClientID + $this.TokenExpirationDate = $Object.TokenExpirationDate + $this.InstallationID = $Object.InstallationID + $this.Permissions = $Object.Permissions + $this.Events = $Object.Events + $this.InstallationType = $Object.InstallationType + $this.InstallationName = $Object.InstallationName } } diff --git a/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 index 345aaf867..fad314e37 100644 --- a/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 @@ -13,29 +13,41 @@ # The token expiration date. # 2024-01-01-00:00:00 - [datetime] $TokenExpirationDate + [System.Nullable[datetime]] $TokenExpirationDate # The refresh token. [securestring] $RefreshToken # The refresh token expiration date. # 2024-01-01-00:00:00 - [datetime] $RefreshTokenExpirationDate + [System.Nullable[datetime]] $RefreshTokenExpirationDate - # Simple parameterless constructor UserGitHubContext() {} - # Creates a context object from a hashtable of key-vaule pairs. - UserGitHubContext([hashtable]$Properties) { - foreach ($Property in $Properties.Keys) { - $this.$Property = $Properties.$Property - } - } - - # Creates a context object from a PSCustomObject. UserGitHubContext([PSCustomObject]$Object) { - $Object.PSObject.Properties | ForEach-Object { - $this.($_.Name) = $_.Value - } + $this.ID = $Object.ID + $this.Name = $Object.Name + $this.DisplayName = $Object.DisplayName + $this.Type = $Object.Type + $this.HostName = $Object.HostName + $this.ApiBaseUri = $Object.ApiBaseUri + $this.ApiVersion = $Object.ApiVersion + $this.AuthType = $Object.AuthType + $this.NodeID = $Object.NodeID + $this.DatabaseID = $Object.DatabaseID + $this.UserName = $Object.UserName + $this.Token = $Object.Token + $this.TokenType = $Object.TokenType + $this.Enterprise = $Object.Enterprise + $this.Owner = $Object.Owner + $this.Repository = $Object.Repository + $this.HttpVersion = $Object.HttpVersion + $this.PerPage = $Object.PerPage + $this.AuthClientID = $Object.AuthClientID + $this.DeviceFlowType = $Object.DeviceFlowType + $this.Scope = $Object.Scope + $this.TokenExpirationDate = $Object.TokenExpirationDate + $this.RefreshToken = $Object.RefreshToken + $this.RefreshTokenExpirationDate = $Object.RefreshTokenExpirationDate } } diff --git a/src/formats/GitHubContext.Format.ps1xml b/src/formats/GitHubContext.Format.ps1xml index 3e3337abe..28a1a0b11 100644 --- a/src/formats/GitHubContext.Format.ps1xml +++ b/src/formats/GitHubContext.Format.ps1xml @@ -26,6 +26,9 @@ + + + @@ -49,6 +52,51 @@ TokenExpirationDate + + + if ($null -eq $_.Remaining) { + return + } + + if ($_.Remaining -lt 0) { + $text = "Expired" + } else { + $text = "$($_.Remaining.Hours)h $($_.Remaining.Minutes)m $($_.Remaining.Seconds)s" + } + + if ($Host.UI.SupportsVirtualTerminal -and + ($env:GITHUB_ACTIONS -ne 'true')) { + switch ($_.AuthType) { + 'UAT' { + $MaxValue = [TimeSpan]::FromHours(8) + } + 'IAT' { + $MaxValue = [TimeSpan]::FromHours(1) + } + } + $ratio = [Math]::Min(($_.Remaining / $MaxValue), 1) + + if ($ratio -ge 1) { + $r = 0 + $g = 255 + } elseif ($ratio -le 0) { + $r = 255 + $g = 0 + } elseif ($ratio -ge 0.5) { + $r = [Math]::Round(255 * (2 - 2 * $ratio)) + $g = 255 + } else { + $r = 255 + $g = [Math]::Round(255 * (2 * $ratio)) + } + $b = 0 + $color = $PSStyle.Foreground.FromRgb($r, $g, $b) + "$color$text$($PSStyle.Reset)" + } else { + $text + } + + diff --git a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 index e6fa3048c..463122e2d 100644 --- a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 @@ -45,10 +45,12 @@ Write-Verbose "Anonymous: [$Anonymous]" if ($Anonymous -or $Context -eq 'Anonymous') { Write-Verbose 'Returning Anonymous context.' - return [GitHubContext]@{ - Name = 'Anonymous' - AuthType = 'Anonymous' - } + return [GitHubContext]::new( + [pscustomobject]@{ + Name = 'Anonymous' + AuthType = 'Anonymous' + } + ) } if ($Context -is [string]) { diff --git a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 index 2e7deec7c..4a9440ab3 100644 --- a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 +++ b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 @@ -73,13 +73,13 @@ Write-Verbose "Converting to: [$($contextObj.Type)GitHubContext]" switch ($contextObj.Type) { 'User' { - [UserGitHubContext]::new($contextObj) + [UserGitHubContext]::new([pscustomobject]$contextObj) } 'App' { - [AppGitHubContext]::new($contextObj) + [AppGitHubContext]::new([pscustomobject]$contextObj) } 'Installation' { - [InstallationGitHubContext]::new($contextObj) + [InstallationGitHubContext]::new([pscustomobject]$contextObj) } default { throw "Unknown context type: [$($contextObj.Type)]" diff --git a/src/types/GitHubContext.Types.ps1xml b/src/types/GitHubContext.Types.ps1xml new file mode 100644 index 000000000..2b1c79e3d --- /dev/null +++ b/src/types/GitHubContext.Types.ps1xml @@ -0,0 +1,27 @@ + + + + UserGitHubContext + + + Remaining + + if ($null -eq $this.TokenExpirationDate) { return } + New-TimeSpan -Start (Get-Date) -End $this.TokenExpirationDate + + + + + + InstallationGitHubContext + + + Remaining + + if ($null -eq $this.TokenExpirationDate) { return } + New-TimeSpan -Start (Get-Date) -End $this.TokenExpirationDate + + + + + From 6b3d855a33ee0096f9cb5b0def8a057c1a629522 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 2 Jul 2025 00:05:53 +0200 Subject: [PATCH 03/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20prereleas?= =?UTF-8?q?e=20to=20`UserAgent`=20header=20(#451)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces changes to the PowerShell module configuration and functionality, focusing on test settings and the `User-Agent` header construction for GitHub API requests. The key updates include skipping specific tests, modifying code coverage targets, and enhancing the `User-Agent` header logic. ### Test configuration updates: * [`.github/PSModule.yml`](diffhunk://#diff-928165ed381f1982eb8f9746a59a2829db4abc8a28eddb8c109e12bb033ff96aR2-R12): Added options to skip tests for `SourceCode`, `PSModule`, and `Module` configurations on both MacOS and Windows platforms. Reduced the `CodeCoverage` target percentage from 50 to 0. ### GitHub API request enhancements: * [`src/functions/public/API/Invoke-GitHubAPI.ps1`](diffhunk://#diff-9285dd3cdd5467d93c8e68c989041171e17993971649b877dce001b1861b2c39L155-R155): Updated the `User-Agent` header to use a new `$script:UserAgent` variable instead of directly referencing `PSModuleInfo.ModuleVersion`. * [`src/variables/private/UserAgent.ps1`](diffhunk://#diff-27a52d639f13708ed22906711cd57c462480c1aae59daf61e35c53a521d1c306R1-R5): Introduced a new script-level variable `$script:UserAgent` that constructs the `User-Agent` header dynamically, incorporating the module version and prerelease information when applicable. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- src/functions/public/API/Invoke-GitHubAPI.ps1 | 2 +- src/variables/private/UserAgent.ps1 | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/variables/private/UserAgent.ps1 diff --git a/src/functions/public/API/Invoke-GitHubAPI.ps1 b/src/functions/public/API/Invoke-GitHubAPI.ps1 index 638c72f81..d4c1047fa 100644 --- a/src/functions/public/API/Invoke-GitHubAPI.ps1 +++ b/src/functions/public/API/Invoke-GitHubAPI.ps1 @@ -152,7 +152,7 @@ function Invoke-GitHubAPI { $headers = @{ Accept = $Accept 'X-GitHub-Api-Version' = $ApiVersion - 'User-Agent' = "PSModule.GitHub $($script:PSModuleInfo.ModuleVersion)" + 'User-Agent' = $script:UserAgent } $headers | Remove-HashtableEntry -NullOrEmptyValues diff --git a/src/variables/private/UserAgent.ps1 b/src/variables/private/UserAgent.ps1 new file mode 100644 index 000000000..384084618 --- /dev/null +++ b/src/variables/private/UserAgent.ps1 @@ -0,0 +1,5 @@ +$script:Prerelease = $script:PSModuleInfo.PrivateData.PSData.Prerelease +$script:UserAgent = "PSModule.GitHub $($script:PSModuleInfo.ModuleVersion)" +if ($script:Prerelease) { + $script:UserAgent += "-$script:Prerelease" +} From 8e7b3d6860add74213a28ae3f0f53aef71c7c90c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 2 Jul 2025 12:03:19 +0200 Subject: [PATCH 04/27] =?UTF-8?q?=F0=9F=AA=B2=20[Fix]:=20Suppress=20output?= =?UTF-8?q?=20of=20functions=20for=20revoking=20access=20tokens=20(#452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request makes small adjustments to improve code clarity and ensure consistent handling of unused return values. Specifically, it updates two functions to explicitly discard the output of the `Invoke-GitHubAPI` command by assigning it to `$null`. Changes to improve code clarity: * [`src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1`](diffhunk://#diff-fd0c42ecf8245c045d9e3798af80e494cd944a2e8ba180bf5719f381f517f689L39-R39): Updated the `Revoke-GitHubAppInstallationAccessToken` function to assign the return value of `Invoke-GitHubAPI` to `$null`, ensuring unused output is explicitly discarded. * [`src/functions/public/Auth/Revoke-GitHubAccessToken.ps1`](diffhunk://#diff-9be3d5b3b006ef480e23f78ee1fa7cb03d19f8973cc39eab75c452e8f59c3730L47-R47): Updated the `Revoke-GitHubAccessToken` function to assign the return value of `Invoke-GitHubAPI` to `$null`, maintaining consistency in handling unused outputs. ## Type of change - [ ] 📖 [Docs] - [x] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- .../GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 | 2 +- src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 b/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 index 99a5cf3b1..a5f6864d6 100644 --- a/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 @@ -36,7 +36,7 @@ function Revoke-GitHubAppInstallationAccessToken { } if ($PSCmdlet.ShouldProcess('GitHub App installation access token', 'Revoke')) { - Invoke-GitHubAPI @InputObject + $null = Invoke-GitHubAPI @InputObject } } diff --git a/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 b/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 index bfddcee90..67791fe8b 100644 --- a/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 +++ b/src/functions/public/Auth/Revoke-GitHubAccessToken.ps1 @@ -44,7 +44,7 @@ Anonymous = $true } if ($PSCmdlet.ShouldProcess('Tokens', 'Revoke')) { - Invoke-GitHubAPI @InputObject + $null = Invoke-GitHubAPI @InputObject } } Write-Debug "[$stackPath] - End" From 78ff3744022439acce064f8c8ba64f2e5f47ebb7 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 2 Jul 2025 16:24:03 +0200 Subject: [PATCH 05/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Widen=20availab?= =?UTF-8?q?ility=20of=20URL=20for=20`GitHubOrganization`=20(#453)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces a new `HostName` parameter to the `GitHubOrganization` class constructor and updates its usage across various functions. The changes ensure that the `Url` property of `GitHubOrganization` objects can dynamically include the hostname when constructing URLs. Additionally, minor error handling improvements were made in one function. ### Updates to `GitHubOrganization` class constructor: * [`src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1`](diffhunk://#diff-ee1cc4e59ef0d0762f150872a9fc2f78c80e9f3d5ce713b9e617fdbaeda48093L139-R139): Added a `HostName` parameter to the `GitHubOrganization` constructor and updated the `Url` property to include the hostname dynamically if provided. [[1]](diffhunk://#diff-ee1cc4e59ef0d0762f150872a9fc2f78c80e9f3d5ce713b9e617fdbaeda48093L139-R139) [[2]](diffhunk://#diff-ee1cc4e59ef0d0762f150872a9fc2f78c80e9f3d5ce713b9e617fdbaeda48093L148-R148) ### Updates to functions using `GitHubOrganization`: * [`src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1`](diffhunk://#diff-0a1f53a3d172fea0035dcdd32a8ca1bfa0441e91f0727c44591b3448b8c9542aL55-R55): Updated calls to the `GitHubOrganization` constructor to pass the `HostName` parameter from the `$Context` object. * `src/functions/private/Organization/Get-GitHubAllOrganization.ps1`, `src/functions/private/Organization/Get-GitHubMyOrganization.ps1`, `src/functions/private/Organization/Get-GitHubUserOrganization.ps1`: Updated calls to the `GitHubOrganization` constructor to pass the `HostName` parameter from the `$Context` object. [[1]](diffhunk://#diff-88b7f49464570f7937d5c2148aed56483c01eb5afaff12cc2ba8c0be9b723e6eL61-R61) [[2]](diffhunk://#diff-e068816595f1abcde1a1fcfa9a80805a5302dadab28d14bd17a224e1f0264352L56-R56) [[3]](diffhunk://#diff-c730abb0f5d97cb7dfd8dfb1aedd31839de272c3f4e714f70f6db26882504e52L58-R60) * `src/functions/private/Organization/Get-GitHubOrganizationByName.ps1`, `src/functions/private/Users/Get-GitHubAllUser.ps1`, `src/functions/public/Organization/Update-GitHubOrganization.ps1`: Updated calls to the `GitHubOrganization` constructor to pass an empty string as the `HostName` parameter when context is unavailable. [[1]](diffhunk://#diff-83fe1cc74ed99f4410b85163cff6dd65affd068817289729bba8aaebb88ec3b7L59-R59) [[2]](diffhunk://#diff-a06e292f87831c3c28fe840f4e7e832f3c5f79043bee587a9e36edbcf13a4ddaL63-R63) [[3]](diffhunk://#diff-eeb2f01e72cb4d2e7bc3bc35152d71f146c8d558aee15fa170031b8f443e17c8L207-R207) ### Error handling improvement: * [`src/functions/private/Users/Get-GitHubUserByName.ps1`](diffhunk://#diff-a2d6056b06ab6b0d2cb714b430a71c01e3ead9c5f890a342379b6969d422c43bR62-R72): Added a `try-catch` block around the `Invoke-GitHubAPI` call to handle potential errors gracefully. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- .../Owner/GitHubOwner/GitHubOrganization.ps1 | 4 ++-- .../Get-GitHubAppInstallableOrganization.ps1 | 2 +- .../Organization/Get-GitHubAllOrganization.ps1 | 2 +- .../Organization/Get-GitHubMyOrganization.ps1 | 2 +- .../Get-GitHubOrganizationByName.ps1 | 2 +- .../Get-GitHubUserOrganization.ps1 | 4 +++- .../private/Users/Get-GitHubAllUser.ps1 | 2 +- .../private/Users/Get-GitHubMyUser.ps1 | 2 +- .../private/Users/Get-GitHubUserByName.ps1 | 18 +++++++++++------- .../Organization/Update-GitHubOrganization.ps1 | 2 +- 10 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 b/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 index bbc1bae4f..5869a6367 100644 --- a/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 +++ b/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 @@ -136,7 +136,7 @@ GitHubOrganization() {} - GitHubOrganization([PSCustomObject]$Object) { + GitHubOrganization([PSCustomObject] $Object, [string] $HostName) { # From GitHubNode $this.ID = $Object.id $this.NodeID = $Object.node_id @@ -145,7 +145,7 @@ $this.Name = $Object.login $this.DisplayName = $Object.name $this.AvatarUrl = $Object.avatar_url - $this.Url = $Object.html_url + $this.Url = $Object.html_url ?? "https://$($HostName)/$($Object.login)" $this.Type = $Object.type $this.Company = $Object.company $this.Blog = $Object.blog diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 index 568e120f4..4d5017e44 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 @@ -52,7 +52,7 @@ Invoke-GitHubAPI @inputObject | ForEach-Object { foreach ($organization in $_.Response) { - [GitHubOrganization]::new($organization) + [GitHubOrganization]::new($organization, $Context.HostName) } } } diff --git a/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 b/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 index 3bf5f6898..98ffe0674 100644 --- a/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 @@ -58,7 +58,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { [GitHubOrganization]::new($_) } + $_.Response | ForEach-Object { [GitHubOrganization]::new($_, $Context.HostName) } } } end { diff --git a/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 b/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 index 718dc43b9..d11b5aebe 100644 --- a/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 @@ -53,7 +53,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { [GitHubOrganization]::new($_) } + $_.Response | ForEach-Object { [GitHubOrganization]::new($_, $Context.HostName) } } } diff --git a/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 b/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 index 629db0ae9..03595108f 100644 --- a/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 +++ b/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 @@ -56,7 +56,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - [GitHubOrganization]::new($_.Response) + [GitHubOrganization]::new($_.Response, '') } } end { diff --git a/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 b/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 index 421a33c3e..6a8df5659 100644 --- a/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 @@ -55,7 +55,9 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { [GitHubOrganization]::new($_) } + foreach ($org in $_.Response) { + [GitHubOrganization]::new($org, $Context.HostName) + } } } end { diff --git a/src/functions/private/Users/Get-GitHubAllUser.ps1 b/src/functions/private/Users/Get-GitHubAllUser.ps1 index 9a1d1283d..43d57fc63 100644 --- a/src/functions/private/Users/Get-GitHubAllUser.ps1 +++ b/src/functions/private/Users/Get-GitHubAllUser.ps1 @@ -60,7 +60,7 @@ Invoke-GitHubAPI @inputObject | ForEach-Object { $_.Response | ForEach-Object { if ($_.type -eq 'Organization') { - [GitHubOrganization]::New($_) + [GitHubOrganization]::New($_, '') } elseif ($_.type -eq 'User') { [GitHubUser]::New($_) } else { diff --git a/src/functions/private/Users/Get-GitHubMyUser.ps1 b/src/functions/private/Users/Get-GitHubMyUser.ps1 index c3da62c86..7526a7837 100644 --- a/src/functions/private/Users/Get-GitHubMyUser.ps1 +++ b/src/functions/private/Users/Get-GitHubMyUser.ps1 @@ -44,7 +44,7 @@ Invoke-GitHubAPI @inputObject | ForEach-Object { if ($_.Response.type -eq 'Organization') { - [GitHubOrganization]::New($_.Response) + [GitHubOrganization]::New($_.Response, $Context.HostName) } elseif ($_.Response.type -eq 'User') { [GitHubUser]::New($_.Response) } else { diff --git a/src/functions/private/Users/Get-GitHubUserByName.ps1 b/src/functions/private/Users/Get-GitHubUserByName.ps1 index 51b5d52cb..701bca251 100644 --- a/src/functions/private/Users/Get-GitHubUserByName.ps1 +++ b/src/functions/private/Users/Get-GitHubUserByName.ps1 @@ -59,14 +59,18 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { - if ($_.Response.type -eq 'Organization') { - [GitHubOrganization]::New($_.Response) - } elseif ($_.Response.type -eq 'User') { - [GitHubUser]::New($_.Response) - } else { - [GitHubOwner]::New($_.Response) + try { + Invoke-GitHubAPI @inputObject | ForEach-Object { + if ($_.Response.type -eq 'Organization') { + [GitHubOrganization]::New($_.Response, $Context.HostName) + } elseif ($_.Response.type -eq 'User') { + [GitHubUser]::New($_.Response) + } else { + [GitHubOwner]::New($_.Response) + } } + } catch { + return } } diff --git a/src/functions/public/Organization/Update-GitHubOrganization.ps1 b/src/functions/public/Organization/Update-GitHubOrganization.ps1 index 5023ec0d8..bfea406da 100644 --- a/src/functions/public/Organization/Update-GitHubOrganization.ps1 +++ b/src/functions/public/Organization/Update-GitHubOrganization.ps1 @@ -204,7 +204,7 @@ if ($PSCmdlet.ShouldProcess("organization [$Name]", 'Set')) { Invoke-GitHubAPI @inputObject | ForEach-Object { - [GitHubOrganization]::new($_.Response) + [GitHubOrganization]::new($_.Response, '') } } } From bb97530973a928cc71688772f498ec6146c3ba08 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 3 Jul 2025 23:59:53 +0200 Subject: [PATCH 06/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Prevent=20Concu?= =?UTF-8?q?rrent=20Access=20Token=20Refresh=20with=20Mutex=20Lock=20(#393)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces significant updates to the GitHub authentication and API handling mechanisms, improving token management, adding support for GitHub App private keys, and enhancing concurrency handling. The changes also include adjustments to data types and configurations for better precision and compatibility. - Fixes #392 ### Authentication Updates * Added support for GitHub App private key handling by introducing a new `PrivateKey` property in `AppGitHubContext` and ensuring it is securely processed during authentication. * Enhanced token refresh logic to handle both user access tokens and GitHub App PEM tokens, with mutex-based concurrency control for token updates. ### API Handling Improvements * Removed redundant token refresh logic from `Invoke-GitHubAPI` and centralized it in the context resolution process for better maintainability. ### Configuration and Type Adjustments * Changed `AccessTokenGracePeriodInHours` from `int` to `double` for increased precision in token expiration calculations. * Updated time-related calculations to use `[datetime]::Now` instead of `Get-Date` for consistency across the module. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug --- src/classes/public/Config/GitHubConfig.ps1 | 2 +- .../GitHubContext/AppGitHubContext.ps1 | 4 + .../Auth/Context/Resolve-GitHubContext.ps1 | 16 ++- .../Test-GitHubAccessTokenRefreshRequired.ps1 | 6 +- .../Update-GitHubUserAccessToken.ps1 | 107 ++++++++++-------- src/functions/public/API/Invoke-GitHubAPI.ps1 | 27 ----- .../public/Auth/Connect-GitHubAccount.ps1 | 11 +- .../public/Auth/Connect-GitHubApp.ps1 | 1 - src/types/GitHubContext.Types.ps1xml | 4 +- src/variables/private/GitHub.ps1 | 2 +- 10 files changed, 93 insertions(+), 87 deletions(-) diff --git a/src/classes/public/Config/GitHubConfig.ps1 b/src/classes/public/Config/GitHubConfig.ps1 index d28d66534..ce745b2de 100644 --- a/src/classes/public/Config/GitHubConfig.ps1 +++ b/src/classes/public/Config/GitHubConfig.ps1 @@ -3,7 +3,7 @@ [string] $ID # The access token grace period in hours. - [System.Nullable[int]] $AccessTokenGracePeriodInHours + [System.Nullable[double]] $AccessTokenGracePeriodInHours # The default context. [string] $DefaultContext diff --git a/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 index e9e795adf..98e1aa4b0 100644 --- a/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 @@ -2,6 +2,9 @@ # Client ID for GitHub Apps [string] $ClientID + # The private key for the app. + [securestring] $PrivateKey + # Owner of the GitHub App [string] $OwnerName @@ -36,6 +39,7 @@ $this.HttpVersion = $Object.HttpVersion $this.PerPage = $Object.PerPage $this.ClientID = $Object.ClientID + $this.PrivateKey = $Object.PrivateKey $this.OwnerName = $Object.OwnerName $this.OwnerType = $Object.OwnerType $this.Permissions = $Object.Permissions diff --git a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 index 463122e2d..5b2253b53 100644 --- a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 @@ -56,12 +56,24 @@ if ($Context -is [string]) { $contextName = $Context Write-Verbose "Getting context: [$contextName]" - return Get-GitHubContext -Context $contextName + $Context = Get-GitHubContext -Context $contextName } if ($null -eq $Context) { Write-Verbose 'Context is null, returning default context.' - return Get-GitHubContext + $Context = Get-GitHubContext + } + + switch ($Context.TokenType) { + 'ghu' { + Write-Verbose 'Using GitHub User Access Token.' + $Context = Update-GitHubUserAccessToken -Context $Context -PassThru + } + 'PEM' { + Write-Verbose 'Using GitHub App PEM Token.' + $jwt = Get-GitHubAppJSONWebToken -ClientId $Context.ClientID -PrivateKey $Context.PrivateKey + $Context.Token = $jwt.Token + } } # TODO: Implement App installation context resolution diff --git a/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 b/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 index 1c2740a09..0692c09df 100644 --- a/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 @@ -27,9 +27,9 @@ process { $tokenExpirationDate = $Context.TokenExpirationDate - $currentDateTime = Get-Date - $remainingDuration = [datetime]$tokenExpirationDate - $currentDateTime - $remainingDuration.TotalHours -lt $script:GitHub.Config.AccessTokenGracePeriodInHours + $remainingDuration = [datetime]$tokenExpirationDate - [datetime]::Now + $updateToken = $remainingDuration.TotalHours -lt $script:GitHub.Config.AccessTokenGracePeriodInHours + $updateToken } end { diff --git a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 index a6ec2dd4f..b67263f90 100644 --- a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 @@ -20,7 +20,7 @@ [Refreshing user access tokens](https://docs.github.com/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens) #> [CmdletBinding(SupportsShouldProcess)] - [OutputType([securestring])] + [OutputType([GitHubContext])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Is the CLI part of the module.')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'The tokens are recieved as clear text. Mitigating exposure by removing variables and performing garbage collection.')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Reason for suppressing')] @@ -32,7 +32,15 @@ # Return the new access token. [Parameter()] - [switch] $PassThru + [switch] $PassThru, + + # Suppress output messages. + [Parameter()] + [switch] $Silent, + + # Timeout in milliseconds for waiting on mutex. Default is 30 seconds. + [Parameter()] + [int] $TimeoutMs = 30000 ) begin { @@ -42,56 +50,63 @@ } process { - Write-Verbose "Reusing previously stored ClientID: [$($Context.AuthClientID)]" - $authClientID = $Context.AuthClientID - $accessTokenValidity = [datetime]($Context.TokenExpirationDate) - (Get-Date) - $accessTokenIsValid = $accessTokenValidity.Seconds -gt 0 - $hours = $accessTokenValidity.Hours.ToString().PadLeft(2, '0') - $minutes = $accessTokenValidity.Minutes.ToString().PadLeft(2, '0') - $seconds = $accessTokenValidity.Seconds.ToString().PadLeft(2, '0') - $accessTokenValidityText = "$hours`:$minutes`:$seconds" - if ($accessTokenIsValid) { - if ($accessTokenValidity.TotalHours -gt $script:GitHub.Config.AccessTokenGracePeriodInHours) { - if (-not $Silent) { - Write-Host '✓ ' -ForegroundColor Green -NoNewline - Write-Host "Access token is still valid for $accessTokenValidityText ..." - } - return - } else { - if (-not $Silent) { - Write-Host '⚠ ' -ForegroundColor Yellow -NoNewline - Write-Host "Access token remaining validity $accessTokenValidityText. Refreshing access token..." + if (Test-GitHubAccessTokenRefreshRequired -Context $Context) { + $lockName = "PSModule.GitHub/$($Context.ID)" + $lock = $null + try { + $lock = [System.Threading.Mutex]::new($false, $lockName) + $updateToken = $lock.WaitOne(0) + + if ($updateToken) { + try { + $refreshTokenValidity = [datetime]($Context.RefreshTokenExpirationDate) - [datetime]::Now + $refreshTokenIsValid = $refreshTokenValidity.TotalSeconds -gt 0 + if ($refreshTokenIsValid) { + if (-not $Silent) { + Write-Host '⚠ ' -ForegroundColor Yellow -NoNewline + Write-Host 'Access token expired. Refreshing access token...' + } + $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $Context.AuthClientID -RefreshToken $Context.RefreshToken -HostName $Context.HostName + } else { + Write-Verbose "Using $($Context.DeviceFlowType) authentication..." + $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $Context.AuthClientID -HostName $Context.HostName + } + $Context.Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token + $Context.TokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.expires_in) + $Context.TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern + $Context.RefreshToken = ConvertTo-SecureString -AsPlainText $tokenResponse.refresh_token + $Context.RefreshTokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.refresh_token_expires_in) + + if ($PSCmdlet.ShouldProcess('Access token', 'Update/refresh')) { + Set-Context -Context $Context -Vault $script:GitHub.ContextVault + } + } finally { + $lock.ReleaseMutex() + } + } else { + Write-Verbose "Access token is not valid. Waiting for mutex to be released (timeout: $($TimeoutMs)ms)..." + try { + if ($lock.WaitOne($TimeoutMs)) { + # Re-read context to get updated token from other process + $Context = Resolve-GitHubContext -Context $Context.ID + $lock.ReleaseMutex() + } else { + Write-Warning 'Timeout waiting for token update. Proceeding with current token state.' + } + } catch [System.Threading.AbandonedMutexException] { + Write-Debug 'Mutex was abandoned by another process. Re-checking token state...' + $Context = Get-Context -Context $Context.ID -Vault $script:GitHub.ContextVault + } } - $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $authClientID -RefreshToken ($Context.RefreshToken) -HostName $Context.HostName - } - } else { - $refreshTokenValidity = [datetime]($Context.RefreshTokenExpirationDate) - (Get-Date) - $refreshTokenIsValid = $refreshTokenValidity.Seconds -gt 0 - if ($refreshTokenIsValid) { - if (-not $Silent) { - Write-Host '⚠ ' -ForegroundColor Yellow -NoNewline - Write-Host 'Access token expired. Refreshing access token...' + } finally { + if ($lock) { + $lock.Dispose() } - $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $authClientID -RefreshToken ($Context.RefreshToken) -HostName $Context.HostName - } else { - Write-Verbose "Using $Mode authentication..." - $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $authClientID -Scope $Scope -HostName $Context.HostName } } - $Context.Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token - $Context.TokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.expires_in) - $Context.TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern - $Context.RefreshToken = ConvertTo-SecureString -AsPlainText $tokenResponse.refresh_token - $Context.RefreshTokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.refresh_token_expires_in) - - if ($PSCmdlet.ShouldProcess('Access token', 'Update/refresh')) { - Set-Context -Context $Context -Vault $script:GitHub.ContextVault - } - if ($PassThru) { - $Context.Token + return $Context } - } end { diff --git a/src/functions/public/API/Invoke-GitHubAPI.ps1 b/src/functions/public/API/Invoke-GitHubAPI.ps1 index d4c1047fa..9261893b5 100644 --- a/src/functions/public/API/Invoke-GitHubAPI.ps1 +++ b/src/functions/public/API/Invoke-GitHubAPI.ps1 @@ -120,7 +120,6 @@ function Invoke-GitHubAPI { process { $Token = $Context.Token - $HttpVersion = Resolve-GitHubContextSetting -Name 'HttpVersion' -Value $HttpVersion -Context $Context $ApiBaseUri = Resolve-GitHubContextSetting -Name 'ApiBaseUri' -Value $ApiBaseUri -Context $Context $ApiVersion = Resolve-GitHubContextSetting -Name 'ApiVersion' -Value $ApiVersion -Context $Context @@ -136,18 +135,6 @@ function Invoke-GitHubAPI { TokenType = $TokenType } | Format-List | Out-String -Stream | ForEach-Object { Write-Debug $_ } } - $jwt = $null - switch ($TokenType) { - 'ghu' { - if (Test-GitHubAccessTokenRefreshRequired -Context $Context) { - $Token = Update-GitHubUserAccessToken -Context $Context -PassThru - } - } - 'PEM' { - $jwt = Get-GitHubAppJSONWebToken -ClientId $Context.ClientID -PrivateKey $Context.Token - $Token = $jwt.Token - } - } $headers = @{ Accept = $Accept @@ -209,20 +196,6 @@ function Invoke-GitHubAPI { Write-Debug '----------------------------------' } do { - switch ($TokenType) { - 'ghu' { - if (Test-GitHubAccessTokenRefreshRequired -Context $Context) { - $Token = Update-GitHubUserAccessToken -Context $Context -PassThru - } - } - 'PEM' { - if ($jwt.ExpiresAt -lt (Get-Date)) { - $jwt = Get-GitHubAppJSONWebToken -ClientId $Context.ClientID -PrivateKey $Context.Token - $Token = $jwt.Token - $APICall['Token'] = $Token - } - } - } $response = Invoke-WebRequest @APICall -ProgressAction 'SilentlyContinue' -Debug:$false -Verbose:$false $headers = @{} diff --git a/src/functions/public/Auth/Connect-GitHubAccount.ps1 b/src/functions/public/Auth/Connect-GitHubAccount.ps1 index c0fe3d3fd..0cbd037ec 100644 --- a/src/functions/public/Auth/Connect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Connect-GitHubAccount.ps1 @@ -98,7 +98,7 @@ Mandatory, ParameterSetName = 'App' )] - [string] $PrivateKey, + [object] $PrivateKey, # Automatically load installations for the GitHub App. [Parameter( @@ -246,10 +246,13 @@ } 'App' { Write-Verbose 'Logging in as a GitHub App...' + if (-not($PrivateKey -is [System.Security.SecureString])) { + $PrivateKey = $PrivateKey | ConvertTo-SecureString -AsPlainText + } $context += @{ - Token = ConvertTo-SecureString -AsPlainText $PrivateKey - TokenType = 'PEM' - ClientID = $ClientID + PrivateKey = $PrivateKey + TokenType = 'PEM' + ClientID = $ClientID } } 'PAT' { diff --git a/src/functions/public/Auth/Connect-GitHubApp.ps1 b/src/functions/public/Auth/Connect-GitHubApp.ps1 index 27661ca33..c74caafba 100644 --- a/src/functions/public/Auth/Connect-GitHubApp.ps1 +++ b/src/functions/public/Auth/Connect-GitHubApp.ps1 @@ -85,7 +85,6 @@ } process { - $installations = Get-GitHubAppInstallation -Context $Context $selectedInstallations = @() Write-Verbose "Found [$($installations.Count)] installations." diff --git a/src/types/GitHubContext.Types.ps1xml b/src/types/GitHubContext.Types.ps1xml index 2b1c79e3d..f76b0b424 100644 --- a/src/types/GitHubContext.Types.ps1xml +++ b/src/types/GitHubContext.Types.ps1xml @@ -7,7 +7,7 @@ Remaining if ($null -eq $this.TokenExpirationDate) { return } - New-TimeSpan -Start (Get-Date) -End $this.TokenExpirationDate + New-TimeSpan -Start ([datetime]::Now) -End $this.TokenExpirationDate @@ -19,7 +19,7 @@ Remaining if ($null -eq $this.TokenExpirationDate) { return } - New-TimeSpan -Start (Get-Date) -End $this.TokenExpirationDate + New-TimeSpan -Start ([datetime]::Now) -End $this.TokenExpirationDate diff --git a/src/variables/private/GitHub.ps1 b/src/variables/private/GitHub.ps1 index 7f372fd8e..883105756 100644 --- a/src/variables/private/GitHub.ps1 +++ b/src/variables/private/GitHub.ps1 @@ -9,7 +9,7 @@ $script:GitHub = [pscustomobject]@{ ID = 'Module' HostName = ($env:GITHUB_SERVER_URL ?? 'github.com') -replace '^https?://' ApiBaseUri = "https://api.$(($env:GITHUB_SERVER_URL ?? 'github.com') -replace '^https?://')" - AccessTokenGracePeriodInHours = 4 + AccessTokenGracePeriodInHours = 4.0 GitHubAppClientID = 'Iv1.f26b61bc99e69405' OAuthAppClientID = '7204ae9b0580f2cb8288' DefaultContext = '' From 12903bc8dcb3122e33a25529559285a65ca5f61f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 4 Jul 2025 21:31:12 +0200 Subject: [PATCH 07/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20function?= =?UTF-8?q?=20to=20`Get-GitHubEnterprise`=20(#460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces significant enhancements to the PowerShell module by adding new functionality for GitHub Enterprise management, improving test coverage, and updating configurations. The most important changes include the addition of new classes to represent enterprise and billing information, a new function to retrieve enterprise details, and comprehensive tests for enterprise-related functionality. ### New functionality for GitHub Enterprise management: * [`src/classes/public/GitHubBillingInfo.ps1`](diffhunk://#diff-38361f5c7ad33bc890c931c733409ac95cb43694afa9c39053ef276ef0cefdceR1-R27): Added a new `GitHubBillingInfo` class to encapsulate billing-related details such as storage usage, bandwidth usage, and license counts. * [`src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1`](diffhunk://#diff-79e51205b5a44da8d9bbe5c3c0c99c828d17fc9aca311beddc5f8130e73f4831R1-R52): Added a new `GitHubEnterprise` class to represent enterprise-level details, including metadata, billing information, and readme content. * [`src/functions/public/Enterprise/Get-GitHubEnterprise.ps1`](diffhunk://#diff-60a0985da8d99410c0dfcb246bd1d808064514c465e945de29d1b3e8b222195fR1-R101): Introduced a new `Get-GitHubEnterprise` function to retrieve detailed information about a GitHub Enterprise instance by name (slug). ### Test coverage improvements: * [`tests/Data/AuthCases.ps1`](diffhunk://#diff-a84e4c5f2270b5b1d0e3ea2f5b4fff03f176502507f4e79b1c2cfb6c9abbc874L67): Updated authentication test cases to include enterprise-specific scenarios. [[1]](diffhunk://#diff-a84e4c5f2270b5b1d0e3ea2f5b4fff03f176502507f4e79b1c2cfb6c9abbc874L67) [[2]](diffhunk://#diff-a84e4c5f2270b5b1d0e3ea2f5b4fff03f176502507f4e79b1c2cfb6c9abbc874R99) * [`tests/Enterprise.ps1`](diffhunk://#diff-4c350f9a2d194e35b7a6b6fa4685bcbcf86dec45ffb52f0b0146d39d6f06bc25R1-R87): Added new tests to verify the functionality of `Get-GitHubEnterprise` and validate enterprise-related data, including billing information and metadata. ### Configuration updates: * [`.github/PSModule.yml`](diffhunk://#diff-928165ed381f1982eb8f9746a59a2829db4abc8a28eddb8c109e12bb033ff96aR2-R12): Updated the test configuration to skip certain tests and set `CodeCoverage.PercentTarget` to `0`. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/PSModule.yml | 2 +- src/classes/public/GitHubBillingInfo.ps1 | 27 +++++ .../Owner/GitHubOwner/GitHubEnterprise.ps1 | 56 ++++++++++ .../Enterprise/Get-GitHubEnterprise.ps1 | 104 ++++++++++++++++++ tests/Data/AuthCases.ps1 | 62 +++++------ tests/Enterprise.ps1 | 86 +++++++++++++++ 6 files changed, 305 insertions(+), 32 deletions(-) create mode 100644 src/classes/public/GitHubBillingInfo.ps1 create mode 100644 src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 create mode 100644 src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 create mode 100644 tests/Enterprise.ps1 diff --git a/.github/PSModule.yml b/.github/PSModule.yml index 6d578178e..c1eb7bd1a 100644 --- a/.github/PSModule.yml +++ b/.github/PSModule.yml @@ -1,3 +1,3 @@ Test: CodeCoverage: - PercentTarget: 50 + PercentTarget: 0 diff --git a/src/classes/public/GitHubBillingInfo.ps1 b/src/classes/public/GitHubBillingInfo.ps1 new file mode 100644 index 000000000..64195a37a --- /dev/null +++ b/src/classes/public/GitHubBillingInfo.ps1 @@ -0,0 +1,27 @@ +class GitHubBillingInfo { + [int]$AllLicensableUsersCount + [int]$AssetPacks + [int]$BandwidthQuota + [int]$BandwidthUsage + [int]$BandwidthUsagePercentage + [int]$StorageQuota + [int]$StorageUsage + [int]$StorageUsagePercentage + [int]$TotalAvailableLicenses + [int]$TotalLicenses + + GitHubBillingInfo() {} + + GitHubBillingInfo([PSCustomObject] $Object) { + $this.AllLicensableUsersCount = $Object.allLicensableUsersCount + $this.AssetPacks = $Object.assetPacks + $this.BandwidthQuota = $Object.bandwidthQuota + $this.BandwidthUsage = $Object.bandwidthUsage + $this.BandwidthUsagePercentage = $Object.bandwidthUsagePercentage + $this.StorageQuota = $Object.storageQuota + $this.StorageUsage = $Object.storageUsage + $this.StorageUsagePercentage = $Object.storageUsagePercentage + $this.TotalAvailableLicenses = $Object.totalAvailableLicenses + $this.TotalLicenses = $Object.totalLicenses + } +} diff --git a/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 b/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 new file mode 100644 index 000000000..790c19625 --- /dev/null +++ b/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 @@ -0,0 +1,56 @@ +class GitHubEnterprise : GitHubOwner { + # The description of the enterprise. + # Example: A great enterprise + [string] $Description + + # The description of the enterprise, as HTML. + # Example:
A great enterprise
+ [string] $DescriptionHTML + + # The billing information for the organization. + [GitHubBillingInfo] $BillingInfo + + # The billing email address for the organization. + # Example: org@example.com + [string] $BillingEmail + + # The readme of the enterprise. + # Example: This is the readme for the enterprise + [string] $Readme + + # The readme of the enterprise, as HTML. + # Example:

This is the readme for the enterprise

+ [string] $ReadmeHTML + + GitHubEnterprise() {} + + GitHubEnterprise([PSCustomObject] $Object) { + # From GitHubNode + $this.ID = $Object.databaseId + $this.NodeID = $Object.id + + # From GitHubOwner + $this.Name = $Object.slug + $this.DisplayName = $Object.name + $this.AvatarUrl = $Object.avatarUrl + $this.Url = $Object.url + $this.Type = $Object.type ?? 'Enterprise' + $this.Company = $Object.company + $this.Blog = $Object.websiteUrl + $this.Location = $Object.location + $this.CreatedAt = $Object.createdAt + $this.UpdatedAt = $Object.updatedAt + + # From GitHubEnterprise + $this.Description = $Object.description + $this.DescriptionHTML = $Object.descriptionHTML + $this.BillingEmail = $Object.billingEmail + $this.BillingInfo = [GitHubBillingInfo]::new($Object.billingInfo) + $this.Readme = $Object.readme + $this.ReadmeHTML = $Object.readmeHTML + } + + [string] ToString() { + return $this.Name + } +} diff --git a/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 b/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 new file mode 100644 index 000000000..079a3a89b --- /dev/null +++ b/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 @@ -0,0 +1,104 @@ +function Get-GitHubEnterprise { + <# + .SYNOPSIS + Retrieves details about a GitHub Enterprise instance by name (slug). + + .DESCRIPTION + This function retrieves detailed information about a GitHub Enterprise instance, including its avatar, billing details, storage usage, + creation date, and other metadata based on the provided name (slug). It returns an object of type GitHubEnterprise populated with this + information. + + .EXAMPLE + Get-GitHubEnterprise -Name 'my-enterprise' + + Output: + ```powershell + Name : My Enterprise + Slug : my-enterprise + URL : https://github.com/enterprises/my-enterprise + CreatedAt : 2022-01-01T00:00:00Z + ViewerIsAdmin : True + ``` + + Retrieves details about the GitHub Enterprise instance named 'my-enterprise'. + + .OUTPUTS + GitHubEnterprise + + .NOTES + An object containing detailed information about the GitHub Enterprise instance, including billing info, URLs, and metadata. + + .LINK + https://psmodule.io/GitHub/Functions/Enterprise/Get-GitHubEnterprise/ + #> + [OutputType([GitHubEnterprise])] + [CmdletBinding()] + param( + # The name (slug) of the GitHub Enterprise instance to retrieve. + [Parameter(Mandatory)] + [Alias('Slug')] + [string] $Name, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $enterpriseQuery = @{ + query = @' +query($Slug: String!) { + enterprise(slug: $Slug) { + avatarUrl + billingEmail + billingInfo { + allLicensableUsersCount + assetPacks + bandwidthQuota + bandwidthUsage + bandwidthUsagePercentage + storageQuota + storageUsage + storageUsagePercentage + totalAvailableLicenses + totalLicenses + } + createdAt + databaseId + description + descriptionHTML + id + location + name + readme + readmeHTML + resourcePath + slug + updatedAt + url + viewerIsAdmin + websiteUrl + } +} +'@ + Variables = @{ + Slug = $Name + } + Context = $Context + } + $enterpriseResult = Invoke-GitHubGraphQLQuery @enterpriseQuery + [GitHubEnterprise]::new($enterpriseResult.enterprise) + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/tests/Data/AuthCases.ps1 b/tests/Data/AuthCases.ps1 index ad252ae73..f09e3ebaa 100644 --- a/tests/Data/AuthCases.ps1 +++ b/tests/Data/AuthCases.ps1 @@ -64,36 +64,36 @@ Organization = 'psmodule-test-org' } } -) -@{ - AuthType = 'App' - Type = 'a GitHub App from an Enterprise' - Case = 'PEM + IAT' - TokenType = 'APP_ENT' - Target = 'organization account' - Owner = 'psmodule-test-org3' - OwnerType = 'organization' - ConnectParams = @{ - ClientID = $env:TEST_APP_ENT_CLIENT_ID - PrivateKey = $env:TEST_APP_ENT_PRIVATE_KEY - } - ConnectAppParams = @{ - Organization = 'psmodule-test-org3' - } -} -@{ - AuthType = 'App' - Type = 'a GitHub App from an Enterprise' - Case = 'PEM + IAT' - TokenType = 'APP_ENT' - Target = 'enterprise account' - Owner = 'msx' - OwnerType = 'enterprise' - ConnectParams = @{ - ClientID = $env:TEST_APP_ENT_CLIENT_ID - PrivateKey = $env:TEST_APP_ENT_PRIVATE_KEY + @{ + AuthType = 'App' + Type = 'a GitHub App from an Enterprise' + Case = 'PEM + IAT' + TokenType = 'APP_ENT' + Target = 'organization account' + Owner = 'psmodule-test-org3' + OwnerType = 'organization' + ConnectParams = @{ + ClientID = $env:TEST_APP_ENT_CLIENT_ID + PrivateKey = $env:TEST_APP_ENT_PRIVATE_KEY + } + ConnectAppParams = @{ + Organization = 'psmodule-test-org3' + } } - ConnectAppParams = @{ - Enterprise = 'msx' + @{ + AuthType = 'App' + Type = 'a GitHub App from an Enterprise' + Case = 'PEM + IAT' + TokenType = 'APP_ENT' + Target = 'enterprise account' + Owner = 'msx' + OwnerType = 'enterprise' + ConnectParams = @{ + ClientID = $env:TEST_APP_ENT_CLIENT_ID + PrivateKey = $env:TEST_APP_ENT_PRIVATE_KEY + } + ConnectAppParams = @{ + Enterprise = 'msx' + } } -} +) diff --git a/tests/Enterprise.ps1 b/tests/Enterprise.ps1 new file mode 100644 index 000000000..9a4760271 --- /dev/null +++ b/tests/Enterprise.ps1 @@ -0,0 +1,86 @@ +#Requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '5.7.1' } + +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', '', + Justification = 'Pester grouping syntax: known issue.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'Used to create a secure string for testing.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Log outputs to GitHub Actions logs.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', '', + Justification = 'Long test descriptions and skip switches' +)] +[CmdletBinding()] +param() + +BeforeAll { + # DEFAULTS ACCROSS ALL TESTS +} + +Describe 'Template' { + $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" + + Context 'As using on ' -ForEach $authCases { + BeforeAll { + $context = Connect-GitHubAccount @connectParams -PassThru -Silent + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + if ($AuthType -eq 'APP') { + It 'Connect-GitHubApp - Connects as a GitHub App to ' { + $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent + LogGroup 'Context - Installation' { + Write-Host ($context | Format-List | Out-String) + } + } + } + } + AfterAll { + Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent + Write-Host ('-' * 60) + } + + It 'Get-GitHubEnterprise - Can get info about an enterprise' -Skip:($OwnerType -notlike 'enterprise') { + $enterprise = Get-GitHubEnterprise -Name $Owner + LogGroup 'Enterprise' { + Write-Host ($enterprise | Select-Object * | Out-String) + } + $enterprise | Should -Not -BeNullOrEmpty + $enterprise | Should -BeOfType 'GitHubEnterprise' + $enterprise.Name | Should -Be 'msx' + $enterprise.DisplayName | Should -Be 'MSX' + $enterprise.ID | Should -Be 15567 + $enterprise.NodeID | Should -Be 'E_kgDNPM8' + $enterprise.AvatarUrl | Should -Be 'https://avatars.githubusercontent.com/b/15567?v=4' + $enterprise.BillingEmail | Should -Be 'marstor@hotmail.com' + $enterprise.Url | Should -Be 'https://github.com/enterprises/msx' + $enterprise.Type | Should -Be 'Enterprise' + $enterprise.BillingInfo | Should -BeOfType 'GitHubBillingInfo' + $enterprise.BillingInfo.AllLicensableUsersCount | Should -Be 1 + $enterprise.BillingInfo.AssetPacks | Should -Be 0 + $enterprise.BillingInfo.BandwidthQuota | Should -Be 5 + $enterprise.BillingInfo.BandwidthUsage | Should -Be 0 + $enterprise.BillingInfo.BandwidthUsagePercentage | Should -Be 0 + $enterprise.BillingInfo.StorageQuota | Should -Be 5 + $enterprise.BillingInfo.StorageUsage | Should -Be 0 + $enterprise.BillingInfo.StorageUsagePercentage | Should -Be 0 + $enterprise.BillingInfo.TotalAvailableLicenses | Should -Be 0 + $enterprise.BillingInfo.TotalLicenses | Should -Be 1 + $enterprise.Readme | Should -Be 'This is a test' + $enterprise.ReadmeHTML | Should -Be '

This is a test

' + $enterprise.CreatedAt | Should -BeOfType 'DateTime' + $enterprise.CreatedAt | Should -Be (Get-Date '18.09.2022 19:53:09') + $enterprise.UpdatedAt | Should -BeOfType 'DateTime' + $enterprise.Description | Should -Be 'This is the description' + $enterprise.DescriptionHTML | Should -Be '
This is the description
' + $enterprise.Location | Should -Be 'Oslo, Norway' + $enterprise.Blog | Should -Be 'https://msx.no' + } + } +} From 7baaed8b67786edbcb239cbb1c0262120bf968a1 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 6 Jul 2025 21:37:58 +0200 Subject: [PATCH 08/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Cleanup=20of=20?= =?UTF-8?q?Context=20usage=20in=20classes,=20and=20functions=20for=20Repos?= =?UTF-8?q?itory=20Rule=20Suites=20(Insights)=20(#461)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces several changes across multiple files to enhance the functionality and structure of GitHub-related classes in the codebase. The most notable updates include replacing `HostName` with `GitHubContext` for improved context management, restructuring properties in `GitHubOwner` subclasses, and updating XML format definitions to reflect the new structure. - Fixes #454 ### Context Management Updates: * Replaced the `HostName` parameter with `GitHubContext` in constructors across multiple classes (`GitHubAppInstallation`, `GitHubArtifact`, `GitHubEnvironment`, `GitHubOrganization`). This change centralizes context-related properties, such as `HostName`, for better scalability and readability. ### GitHubOwner Class Restructuring: * Removed redundant properties (e.g., `Company`, `Blog`, `Plan`) from the `GitHubOwner` class and its subclasses (`GitHubEnterprise`, `GitHubOrganization`, `GitHubUser`). Added new properties such as `Description` and `Website` to better align with GraphQL schema mappings. ### GraphQL Mapping Enhancements: * Introduced static `$PropertyToGraphQLMap` hashtables in `GitHubEnterprise` and `GitHubOrganization` classes to define mappings between class properties and GraphQL fields, improving maintainability and integration with GraphQL APIs. ### XML Format Updates: * Updated the `GitHubOwner.Format.ps1xml` file to include new properties (`DisplayName`, `CreatedAt`) in table views for improved visualization of `GitHubOwner` objects. Removed deprecated columns such as `Company` and `Plan`. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- .github/PSModule.yml | 2 +- .../public/App/GitHubAppInstallation.ps1 | 6 +- .../public/Artifacts/GitHubArtifact.ps1 | 4 +- .../public/Environment/GitHubEnvironment.ps1 | 3 +- src/classes/public/Owner/GitHubOwner.ps1 | 53 ++------- .../Owner/GitHubOwner/GitHubEnterprise.ps1 | 39 +++---- .../Owner/GitHubOwner/GitHubOrganization.ps1 | 92 ++++++++++++---- .../public/Owner/GitHubOwner/GitHubUser.ps1 | 52 +++++++-- src/formats/GitHubOwner.Format.ps1xml | 33 +++--- .../Get-GitHubAppInstallableOrganization.ps1 | 2 +- ...tHubAppInstallationForAuthenticatedApp.ps1 | 4 +- .../GitHub Apps/Get-GitHubAppJSONWebToken.ps1 | 1 - ...bEnterpriseOrganizationAppInstallation.ps1 | 2 +- .../New-GitHubAppInstallationAccessToken.ps1 | 13 +-- .../Artifacts/Get-GitHubArtifactById.ps1 | 2 +- .../Get-GitHubArtifactFromRepository.ps1 | 2 +- .../Get-GitHubArtifactFromWorkflowRun.ps1 | 2 +- .../Auth/Context/Remove-GitHubContext.ps1 | 1 - .../Enterprise/Get-GitHubEnterpriseByName.ps1 | 74 +++++++++++++ .../Enterprise/Get-GitHubEnterpriseList.ps1 | 100 +++++++++++++++++ .../Get-GitHubEnvironmentByName.ps1 | 5 +- .../Get-GitHubEnvironmentList.ps1 | 6 +- .../Get-GitHubAllOrganization.ps1 | 4 +- .../Organization/Get-GitHubMyOrganization.ps1 | 63 ----------- .../Get-GitHubOrganizationByName.ps1 | 2 +- .../Get-GitHubOrganizationListForAuthUser.ps1 | 104 ++++++++++++++++++ .../Get-GitHubUserOrganization.ps1 | 4 +- .../Get-GitHubRepositoryRuleSuiteById.ps1 | 5 - .../Get-GitHubRepositoryRuleSuiteList.ps1 | 4 - .../private/Users/Get-GitHubAllUser.ps1 | 12 +- .../private/Users/Get-GitHubMyUser.ps1 | 2 +- .../private/Users/Get-GitHubUserByName.ps1 | 2 +- .../public/Auth/Connect-GitHubApp.ps1 | 2 +- .../Enterprise/Get-GitHubEnterprise.ps1 | 80 ++++++-------- .../Environments/Set-GitHubEnvironment.ps1 | 4 +- .../Organization/Get-GitHubOrganization.ps1 | 2 +- .../Members/Get-GitHubOrganizationMember.ps1 | 4 +- .../Update-GitHubOrganization.ps1 | 12 +- .../Get-GitHubRepositorySecurityFix.ps1 | 1 - .../Get-GitHubRepositoryRuleSuite.ps1 | 1 - .../public/Users/Update-GitHubUser.ps1 | 16 +-- src/types/GitHubUser.Types.ps1xml | 8 ++ .../{Enterprise.ps1 => Enterprise.Tests.ps1} | 24 +--- tests/Organizations.Tests.ps1 | 2 +- tests/Users.Tests.ps1 | 4 + 45 files changed, 534 insertions(+), 326 deletions(-) create mode 100644 src/functions/private/Enterprise/Get-GitHubEnterpriseByName.ps1 create mode 100644 src/functions/private/Enterprise/Get-GitHubEnterpriseList.ps1 delete mode 100644 src/functions/private/Organization/Get-GitHubMyOrganization.ps1 create mode 100644 src/functions/private/Organization/Get-GitHubOrganizationListForAuthUser.ps1 rename src/functions/{public => private}/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 (94%) rename src/functions/{public => private}/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 (96%) rename tests/{Enterprise.ps1 => Enterprise.Tests.ps1} (66%) diff --git a/.github/PSModule.yml b/.github/PSModule.yml index c1eb7bd1a..6d578178e 100644 --- a/.github/PSModule.yml +++ b/.github/PSModule.yml @@ -1,3 +1,3 @@ Test: CodeCoverage: - PercentTarget: 0 + PercentTarget: 50 diff --git a/src/classes/public/App/GitHubAppInstallation.ps1 b/src/classes/public/App/GitHubAppInstallation.ps1 index 5335e4830..96fd2831c 100644 --- a/src/classes/public/App/GitHubAppInstallation.ps1 +++ b/src/classes/public/App/GitHubAppInstallation.ps1 @@ -65,7 +65,7 @@ $this.Url = $Object.html_url } - GitHubAppInstallation([PSCustomObject] $Object, [string] $Target, [string] $Type, [string] $HostName) { + GitHubAppInstallation([PSCustomObject] $Object, [string] $Target, [string] $Type, [GitHubContext] $Context) { $this.ID = $Object.id $this.App = [GitHubApp]::new( [PSCustomObject]@{ @@ -77,7 +77,7 @@ $this.Target = [GitHubOwner]@{ Name = $Target Type = $Type - Url = "https://$HostName/$Target" + Url = "https://$($Context.HostName)/$Target" } $this.Type = $Type $this.RepositorySelection = $Object.repository_selection @@ -88,6 +88,6 @@ $this.UpdatedAt = $Object.updated_at $this.SuspendedAt = $Object.suspended_at $this.SuspendedBy = [GitHubUser]::new($Object.suspended_by) - $this.Url = "https://$HostName/$($Type.ToLower())s/$Target/settings/installations/$($Object.id)" + $this.Url = "https://$($Context.HostName)/$($Type.ToLower())s/$Target/settings/installations/$($Object.id)" } } diff --git a/src/classes/public/Artifacts/GitHubArtifact.ps1 b/src/classes/public/Artifacts/GitHubArtifact.ps1 index 3e654860e..988c09931 100644 --- a/src/classes/public/Artifacts/GitHubArtifact.ps1 +++ b/src/classes/public/Artifacts/GitHubArtifact.ps1 @@ -37,14 +37,14 @@ GitHubArtifact() {} - GitHubArtifact([PSCustomObject]$Object, [string]$Owner, [string]$Repository, [string]$HostName) { + GitHubArtifact([PSCustomObject]$Object, [string]$Owner, [string]$Repository, [GitHubContext]$Context) { $this.ID = $Object.id $this.NodeID = $Object.node_id $this.Name = $Object.name $this.Owner = $Owner $this.Repository = $Repository $this.Size = $Object.size_in_bytes - $this.Url = "https://$($HostName)/$Owner/$Repository/actions/runs/$($Object.workflow_run.id)/artifacts/$($Object.id)" + $this.Url = "https://$($Context.HostName)/$Owner/$Repository/actions/runs/$($Object.workflow_run.id)/artifacts/$($Object.id)" $this.ArchiveDownloadUrl = $Object.archive_download_url $this.Expired = $Object.expired $this.Digest = $Object.digest diff --git a/src/classes/public/Environment/GitHubEnvironment.ps1 b/src/classes/public/Environment/GitHubEnvironment.ps1 index 4da7639c7..799addd97 100644 --- a/src/classes/public/Environment/GitHubEnvironment.ps1 +++ b/src/classes/public/Environment/GitHubEnvironment.ps1 @@ -28,12 +28,13 @@ GitHubEnvironment() {} - GitHubEnvironment([PSCustomObject]$Object, [string]$Owner, [string]$Repository) { + GitHubEnvironment([PSCustomObject]$Object, [string]$Owner, [string]$Repository, [GitHubContext]$Context) { $this.ID = $Object.id $this.NodeID = $Object.node_id $this.Name = $Object.name $this.Owner = $Owner $this.Repository = $Repository + $this.Url = "https://$($Context.HostName)/$Owner/$Repository/settings/environments/$($Object.id)/edit" $this.CreatedAt = $Object.created_at $this.UpdatedAt = $Object.updated_at $this.AdminsCanBypass = $Object.can_admins_bypass diff --git a/src/classes/public/Owner/GitHubOwner.ps1 b/src/classes/public/Owner/GitHubOwner.ps1 index cc932ce1a..81efa24b0 100644 --- a/src/classes/public/Owner/GitHubOwner.ps1 +++ b/src/classes/public/Owner/GitHubOwner.ps1 @@ -19,41 +19,17 @@ # Example: User [string] $Type - # The company the account is affiliated with. - # Example: GitHub - [string] $Company - - # The blog URL of the account. - # Example: https://github.com/blog - [string] $Blog - # The location of the account. # Example: San Francisco [string] $Location - # The email of the account. - # Example: octocat@github.com - [string] $Email - - # The Twitter username. - # Example: monalisa - [string] $TwitterUsername - - # The number of public repositories. - # Example: 2 - [System.Nullable[uint]] $PublicRepos + # The description of the organization. + # Example: A great organization + [string] $Description - # The number of public gists. - # Example: 1 - [System.Nullable[uint]] $PublicGists - - # The number of followers. - # Example: 20 - [System.Nullable[uint]] $Followers - - # The number of accounts this account is following. - # Example: 0 - [System.Nullable[uint]] $Following + # The website URL of the account. + # Example: https://github.com/blog + [string] $Website # The creation date of the account. # Example: 2008-01-14T04:33:35Z @@ -63,10 +39,6 @@ # Example: 2008-01-14T04:33:35Z [System.Nullable[datetime]] $UpdatedAt - # The user's plan. - # Includes: Name, Collaborators, PrivateRepos, Space - [GitHubPlan] $Plan - GitHubOwner() {} GitHubOwner([PSCustomObject]$Object) { @@ -78,20 +50,13 @@ $this.Name = $Object.slug ?? $Object.login $this.DisplayName = $Object.name $this.AvatarUrl = $Object.avatar_url - $this.Url = $Object.html_url + $this.Url = $Object.html_url ?? $Object.url $this.Type = $Object.type - $this.Company = $Object.company - $this.Blog = $Object.website_url ?? $Object.blog $this.Location = $Object.location - $this.Email = $Object.email - $this.TwitterUsername = $Object.twitter_username - $this.PublicRepos = $Object.public_repos - $this.PublicGists = $Object.public_gists - $this.Followers = $Object.followers - $this.Following = $Object.following + $this.Description = $Object.description ?? $Object.bio + $this.Website = $Object.websiteUrl ?? $Object.blog $this.CreatedAt = $Object.created_at $this.UpdatedAt = $Object.updated_at - $this.Plan = [GitHubPlan]::New($Object.plan) } [string] ToString() { diff --git a/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 b/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 index 790c19625..66fea40c4 100644 --- a/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 +++ b/src/classes/public/Owner/GitHubOwner/GitHubEnterprise.ps1 @@ -1,19 +1,4 @@ class GitHubEnterprise : GitHubOwner { - # The description of the enterprise. - # Example: A great enterprise - [string] $Description - - # The description of the enterprise, as HTML. - # Example:
A great enterprise
- [string] $DescriptionHTML - - # The billing information for the organization. - [GitHubBillingInfo] $BillingInfo - - # The billing email address for the organization. - # Example: org@example.com - [string] $BillingEmail - # The readme of the enterprise. # Example: This is the readme for the enterprise [string] $Readme @@ -22,6 +7,22 @@ # Example:

This is the readme for the enterprise

[string] $ReadmeHTML + static [hashtable] $PropertyToGraphQLMap = @{ + ID = 'databaseId' + NodeID = 'id' + Name = 'slug' + DisplayName = 'name' + AvatarUrl = 'avatarUrl' + Url = 'url' + Website = 'websiteUrl' + Location = 'location' + CreatedAt = 'createdAt' + UpdatedAt = 'updatedAt' + Description = 'description' + Readme = 'readme' + ReadmeHTML = 'readmeHTML' + } + GitHubEnterprise() {} GitHubEnterprise([PSCustomObject] $Object) { @@ -35,17 +36,13 @@ $this.AvatarUrl = $Object.avatarUrl $this.Url = $Object.url $this.Type = $Object.type ?? 'Enterprise' - $this.Company = $Object.company - $this.Blog = $Object.websiteUrl $this.Location = $Object.location + $this.Description = $Object.description + $this.Website = $Object.websiteUrl $this.CreatedAt = $Object.createdAt $this.UpdatedAt = $Object.updatedAt # From GitHubEnterprise - $this.Description = $Object.description - $this.DescriptionHTML = $Object.descriptionHTML - $this.BillingEmail = $Object.billingEmail - $this.BillingInfo = [GitHubBillingInfo]::new($Object.billingInfo) $this.Readme = $Object.readme $this.ReadmeHTML = $Object.readmeHTML } diff --git a/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 b/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 index 5869a6367..48528dba2 100644 --- a/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 +++ b/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 @@ -1,7 +1,31 @@ class GitHubOrganization : GitHubOwner { - # The description of the organization. - # Example: A great organization - [string] $Description + # The email of the account. + # Example: octocat@github.com + [string] $Email + + # The Twitter username. + # Example: monalisa + [string] $TwitterUsername + + # The user's plan. + # Includes: Name, Collaborators, PrivateRepos, Space + [GitHubPlan] $Plan + + # The number of public repositories. + # Example: 2 + [System.Nullable[uint]] $PublicRepos + + # The number of public gists. + # Example: 1 + [System.Nullable[uint]] $PublicGists + + # The number of followers. + # Example: 20 + [System.Nullable[uint]] $Followers + + # The number of accounts this account is following. + # Example: 0 + [System.Nullable[uint]] $Following # The number of private gists. # Example: 81 @@ -49,7 +73,7 @@ # Whether two-factor authentication is required for members. # Example: $true - [System.Nullable[bool]] $TwoFactorRequirementEnabled + [System.Nullable[bool]] $RequiresTwoFactorAuthentication # The type of repositories members can create. # Example: all @@ -134,54 +158,74 @@ # The date and time when the organization was archived, if applicable. [System.Nullable[datetime]] $ArchivedAt + static [hashtable] $PropertyToGraphQLMap = @{ + ArchivedAt = 'archivedAt' + AvatarUrl = 'avatarUrl' + CreatedAt = 'createdAt' + Description = 'description' + DisplayName = 'name' + Email = 'email' + ID = 'databaseId' + Location = 'location' + Name = 'login' + NodeID = 'id' + IsVerified = 'isVerified' + # MembersCanForkPrivateRepositories = 'membersCanForkPrivateRepositories' + # RequiresTwoFactorAuthentication = 'requiresTwoFactorAuthentication' + TwitterUsername = 'twitterUsername' + UpdatedAt = 'updatedAt' + Url = 'url' + # RequireWebCommitSignoff = 'webCommitSignoffRequired' + Website = 'websiteUrl' + } + GitHubOrganization() {} - GitHubOrganization([PSCustomObject] $Object, [string] $HostName) { + GitHubOrganization([PSCustomObject] $Object, [GitHubContext] $Context) { # From GitHubNode - $this.ID = $Object.id - $this.NodeID = $Object.node_id + $this.ID = $Object.databaseId ?? $Object.id + $this.NodeID = $Object.node_id ?? $Object.id # From GitHubOwner $this.Name = $Object.login $this.DisplayName = $Object.name - $this.AvatarUrl = $Object.avatar_url - $this.Url = $Object.html_url ?? "https://$($HostName)/$($Object.login)" - $this.Type = $Object.type - $this.Company = $Object.company - $this.Blog = $Object.blog + $this.AvatarUrl = $Object.avatar_url ?? $Object.avatarUrl + $this.Url = $Object.html_url ?? $Object.url ?? "https://$($Context.HostName)/$($Object.login)" + $this.Type = $Object.type ?? 'Organization' $this.Location = $Object.location + $this.Description = $Object.description + $this.Website = $Object.website ?? $Object.blog + $this.CreatedAt = $Object.created_at ?? $Object.createdAt + $this.UpdatedAt = $Object.updated_at ?? $Object.updatedAt + + # From GitHubOrganization $this.Email = $Object.email - $this.TwitterUsername = $Object.twitter_username + $this.TwitterUsername = $Object.twitter_username ?? $Object.twitterUsername + $this.Plan = [GitHubPlan]::New($Object.plan) $this.PublicRepos = $Object.public_repos $this.PublicGists = $Object.public_gists $this.Followers = $Object.followers $this.Following = $Object.following - $this.CreatedAt = $Object.created_at - $this.UpdatedAt = $Object.updated_at - $this.Plan = [GitHubPlan]::New($Object.plan) - - # From GitHubOrganization - $this.Description = $Object.description $this.PrivateGists = $Object.total_private_gists $this.TotalPrivateRepos = $Object.total_private_repos $this.OwnedPrivateRepos = $Object.owned_private_repos $this.DiskUsage = $Object.disk_usage $this.Collaborators = $Object.collaborators - $this.IsVerified = $Object.is_verified + $this.IsVerified = $Object.is_verified ?? $Object.isVerified $this.HasOrganizationProjects = $Object.has_organization_projects $this.HasRepositoryProjects = $Object.has_repository_projects $this.BillingEmail = $Object.billing_email $this.DefaultRepositoryPermission = $Object.default_repository_permission $this.MembersCanCreateRepositories = $Object.members_can_create_repositories - $this.TwoFactorRequirementEnabled = $Object.two_factor_requirement_enabled + $this.RequiresTwoFactorAuthentication = $Object.two_factor_requirement_enabled ?? $Object.requiresTwoFactorAuthentication $this.MembersAllowedRepositoryCreationType = $Object.members_allowed_repository_creation_type $this.MembersCanCreatePublicRepositories = $Object.members_can_create_public_repositories $this.MembersCanCreatePrivateRepositories = $Object.members_can_create_private_repositories $this.MembersCanCreateInternalRepositories = $Object.members_can_create_internal_repositories $this.MembersCanInviteCollaborators = $Object.members_can_invite_collaborators $this.MembersCanCreatePages = $Object.members_can_create_pages - $this.MembersCanForkPrivateRepositories = $Object.members_can_fork_private_repositories - $this.RequireWebCommitSignoff = $Object.web_commit_signoff_required + $this.MembersCanForkPrivateRepositories = $Object.members_can_fork_private_repositories ?? $Object.membersCanForkPrivateRepositories + $this.RequireWebCommitSignoff = $Object.web_commit_signoff_required ?? $Object.requiresTwoFactorAuthentication $this.DeployKeysEnabledForRepositories = $Object.deploy_keys_enabled_for_repositories $this.MembersCanCreatePublicPages = $Object.members_can_create_public_pages $this.MembersCanCreatePrivatePages = $Object.members_can_create_private_pages @@ -194,7 +238,7 @@ $this.SecretScanningPushProtectionCustomLinkEnabled = $Object.secret_scanning_push_protection_custom_link_enabled $this.SecretScanningPushProtectionCustomLink = $Object.secret_scanning_push_protection_custom_link $this.SecretScanningValidityChecksEnabled = $Object.secret_scanning_validity_checks_enabled - $this.ArchivedAt = $Object.archived_at + $this.ArchivedAt = $Object.archived_at ?? $Object.archivedAt } [string] ToString() { diff --git a/src/classes/public/Owner/GitHubOwner/GitHubUser.ps1 b/src/classes/public/Owner/GitHubOwner/GitHubUser.ps1 index b6b1d4664..a9e4e4abe 100644 --- a/src/classes/public/Owner/GitHubOwner/GitHubUser.ps1 +++ b/src/classes/public/Owner/GitHubOwner/GitHubUser.ps1 @@ -1,15 +1,43 @@ class GitHubUser : GitHubOwner { + # The email of the account. + # Example: octocat@github.com + [string] $Email + # Whether the user is hireable. [System.Nullable[bool]] $Hireable - # The user's biography. - # Example: There once was... - [string] $Bio + # The company the account is affiliated with. + # Example: GitHub + [string] $Company + + # The Twitter username. + # Example: monalisa + [string] $TwitterUsername + + # The number of public repositories. + # Example: 2 + [System.Nullable[uint]] $PublicRepos + + # The number of public gists. + # Example: 1 + [System.Nullable[uint]] $PublicGists + + # The number of followers. + # Example: 20 + [System.Nullable[uint]] $Followers + + # The number of accounts this account is following. + # Example: 0 + [System.Nullable[uint]] $Following # The notification email address of the user. # Example: octocat@github.com [string] $NotificationEmail + # The user's plan. + # Includes: Name, Collaborators, PrivateRepos, Space + [GitHubPlan] $Plan + GitHubUser() {} GitHubUser([PSCustomObject]$Object) { @@ -23,23 +51,23 @@ $this.AvatarUrl = $Object.avatar_url $this.Url = $Object.html_url $this.Type = $Object.type - $this.Company = $Object.company - $this.Blog = $Object.blog $this.Location = $Object.location + $this.Description = $Object.bio + $this.Website = $Object.blog + $this.CreatedAt = $Object.created_at + $this.UpdatedAt = $Object.updated_at + + # From GitHubUser $this.Email = $Object.email + $this.Hireable = $Object.hireable + $this.Company = $Object.company $this.TwitterUsername = $Object.twitter_username $this.PublicRepos = $Object.public_repos $this.PublicGists = $Object.public_gists $this.Followers = $Object.followers $this.Following = $Object.following - $this.CreatedAt = $Object.created_at - $this.UpdatedAt = $Object.updated_at - $this.Plan = [GitHubPlan]::New($Object.plan) - - # From GitHubUser - $this.Hireable = $Object.hireable - $this.Bio = $Object.bio $this.NotificationEmail = $Object.notification_email + $this.Plan = [GitHubPlan]::New($Object.plan) } [string] ToString() { diff --git a/src/formats/GitHubOwner.Format.ps1xml b/src/formats/GitHubOwner.Format.ps1xml index 34d050cd5..c1d8dcb3f 100644 --- a/src/formats/GitHubOwner.Format.ps1xml +++ b/src/formats/GitHubOwner.Format.ps1xml @@ -7,9 +7,13 @@ GitHubOwner GitHubUser GitHubOrganization + GitHubEnterprise + + + @@ -20,15 +24,15 @@ - - - - + + + DisplayName + if ($Host.UI.SupportsVirtualTerminal -and @@ -46,10 +50,7 @@ Type - Company - - - Plan + CreatedAt @@ -65,6 +66,9 @@ + + DisplayName + Name @@ -74,9 +78,6 @@ NodeID - - DisplayName - AvatarUrl @@ -86,9 +87,6 @@ Type - - Company - Location @@ -96,10 +94,10 @@ Email - TwitterUsername + Description - Blog + Website CreatedAt @@ -107,9 +105,6 @@ UpdatedAt - - Plan - diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 index 4d5017e44..5c03bfcfb 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 @@ -52,7 +52,7 @@ Invoke-GitHubAPI @inputObject | ForEach-Object { foreach ($organization in $_.Response) { - [GitHubOrganization]::new($organization, $Context.HostName) + [GitHubOrganization]::new($organization, $Context) } } } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 index f4dfcb18e..a4a218574 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 @@ -47,8 +47,8 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { - [GitHubAppInstallation]::new($_) + foreach ($installation in $_.Response) { + [GitHubAppInstallation]::new($installation) } } } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 index 133816e4f..9ac33c835 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 @@ -37,7 +37,6 @@ )] [CmdletBinding(DefaultParameterSetName = 'PrivateKey')] - [Alias('Get-GitHubAppJWT')] [OutputType([GitHubJsonWebToken])] param( # The client ID of the GitHub App. diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 index 4609f1fe1..ea19a3c4d 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 @@ -62,7 +62,7 @@ Invoke-GitHubAPI @inputObject | ForEach-Object { foreach ($installation in $_.Response) { - [GitHubAppInstallation]::new($installation, $Organization, 'Organization', $context.HostName) + [GitHubAppInstallation]::new($installation, $Organization, 'Organization', $Context) } } } diff --git a/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 index 2291149ad..34369ff47 100644 --- a/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 +++ b/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 @@ -48,18 +48,15 @@ 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'No state is changed.' )] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', - Justification = 'The tokens are received as clear text. Mitigating exposure by removing variables and performing garbage collection.')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'The tokens are received as clear text. Mitigating exposure by removing variables and performing garbage collection.' + )] [CmdletBinding()] param( # The unique identifier of the installation. # Example: '12345678' - [Parameter( - Mandatory, - ValueFromPipeline, - ValueFromPipelineByPropertyName - )] - [Alias('installation_id', 'InstallationID')] + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [int] $ID, # The context to run the command in. Used to get the details for the API call. diff --git a/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 b/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 index 1d634fbbb..782667043 100644 --- a/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 +++ b/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 @@ -68,7 +68,7 @@ function Get-GitHubArtifactById { } Invoke-GitHubAPI @inputObject | ForEach-Object { - [GitHubArtifact]::new($_.Response, $Owner, $Repository, $Context.HostName) + [GitHubArtifact]::new($_.Response, $Owner, $Repository, $Context) } } diff --git a/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 b/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 index d7f86c044..08087d229 100644 --- a/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 +++ b/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 @@ -88,7 +88,7 @@ function Get-GitHubArtifactFromRepository { } $artifacts | ForEach-Object { - [GitHubArtifact]::new($_, $Owner, $Repository, $Context.HostName) + [GitHubArtifact]::new($_, $Owner, $Repository, $Context) } } diff --git a/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 b/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 index a7b9b863b..7a54c1709 100644 --- a/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 +++ b/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 @@ -99,7 +99,7 @@ function Get-GitHubArtifactFromWorkflowRun { } $artifacts | ForEach-Object { - [GitHubArtifact]::new($_, $Owner, $Repository, $Context.HostName) + [GitHubArtifact]::new($_, $Owner, $Repository, $Context) } } diff --git a/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 b/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 index 4c93f5ddc..9b6f810d8 100644 --- a/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 @@ -23,7 +23,6 @@ param( # The name of the context. [Parameter(Mandatory)] - [Alias('Name')] [string] $Context ) diff --git a/src/functions/private/Enterprise/Get-GitHubEnterpriseByName.ps1 b/src/functions/private/Enterprise/Get-GitHubEnterpriseByName.ps1 new file mode 100644 index 000000000..81d33aa5d --- /dev/null +++ b/src/functions/private/Enterprise/Get-GitHubEnterpriseByName.ps1 @@ -0,0 +1,74 @@ +function Get-GitHubEnterpriseByName { + <# + .SYNOPSIS + Retrieves details about a GitHub Enterprise instance by name (slug). + + .DESCRIPTION + This function retrieves detailed information about a GitHub Enterprise instance, including its avatar, billing details, storage usage, + creation date, and other metadata based on the provided name (slug). It returns an object of type GitHubEnterprise populated with this + information. + + .EXAMPLE + Get-GitHubEnterpriseByName -Name 'my-enterprise' + + Output: + ```powershell + Name : My Enterprise + Slug : my-enterprise + URL : https://github.com/enterprises/my-enterprise + CreatedAt : 2022-01-01T00:00:00Z + ViewerIsAdmin : True + ``` + + Retrieves details about the GitHub Enterprise instance named 'my-enterprise'. + + .OUTPUTS + GitHubEnterprise + + .NOTES + An object containing detailed information about the GitHub Enterprise instance, including billing info, URLs, and metadata. + #> + [OutputType([GitHubEnterprise])] + [CmdletBinding()] + param( + # The name (slug) of the GitHub Enterprise instance to retrieve. + [Parameter(Mandatory)] + [Alias('Slug')] + [string] $Name, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $graphQLFields = ([GitHubEnterprise]::PropertyToGraphQLMap).Values + + $enterpriseQuery = @{ + query = @" +query(`$Slug: String!) { + enterprise(slug: `$Slug) { + $graphQLFields + } +} +"@ + Variables = @{ + Slug = $Name + } + Context = $Context + } + $enterpriseResult = Invoke-GitHubGraphQLQuery @enterpriseQuery + [GitHubEnterprise]::new($enterpriseResult.enterprise) + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Enterprise/Get-GitHubEnterpriseList.ps1 b/src/functions/private/Enterprise/Get-GitHubEnterpriseList.ps1 new file mode 100644 index 000000000..cd2f890e4 --- /dev/null +++ b/src/functions/private/Enterprise/Get-GitHubEnterpriseList.ps1 @@ -0,0 +1,100 @@ +function Get-GitHubEnterpriseList { + <# + .SYNOPSIS + Retrieves a list of all GitHub Enterprise instances. + + .DESCRIPTION + This function retrieves detailed information about all GitHub Enterprise instances, including their avatars, billing details, storage usage, + creation dates, and other metadata. It returns an array of objects of type GitHubEnterprise populated with this information. + + .EXAMPLE + Get-GitHubEnterpriseList + + Output: + ```powershell + Name : My Enterprise + Slug : my-enterprise + URL : https://github.com/enterprises/my-enterprise + CreatedAt : 2022-01-01T00:00:00Z + + Name : Another Enterprise + Slug : another-enterprise + URL : https://github.com/enterprises/another-enterprise + CreatedAt : 2021-12-01T00:00:00Z + ``` + + Retrieves details about the GitHub Enterprise instance. + + .OUTPUTS + GitHubEnterprise[] + + .NOTES + An array of objects containing detailed information about the GitHub Enterprise instances, including billing info, URLs, and metadata. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', 'hasNextPage', Scope = 'Function', + Justification = 'Unknown issue with var scoping in blocks.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', 'after', Scope = 'Function', + Justification = 'Unknown issue with var scoping in blocks.' + )] + [OutputType([GitHubEnterprise[]])] + [CmdletBinding()] + param( + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $hasNextPage = $false + $after = $null + $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context + + $graphQLFields = ([GitHubEnterprise]::PropertyToGraphQLMap).Values + + do { + $enterpriseQuery = @{ + query = @" +query(`$perPage: Int!, `$after: String) { + viewer { + enterprises(first: `$perPage, after: `$after) { + nodes { + $graphQLFields + } + pageInfo { + endCursor + hasNextPage + } + } + } +} +"@ + Variables = @{ + perPage = $perPageSetting + after = $after + } + Context = $Context + } + Invoke-GitHubGraphQLQuery @enterpriseQuery | ForEach-Object { + foreach ($enterprise in $_.viewer.enterprises.nodes) { + [GitHubEnterprise]::new($enterprise) + } + $hasNextPage = $_.viewer.enterprises.pageInfo.hasNextPage + $after = $_.viewer.enterprises.pageInfo.endCursor + } + } while ($hasNextPage) + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 b/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 index d4286cb88..0b9df7f01 100644 --- a/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 +++ b/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 @@ -50,7 +50,6 @@ filter Get-GitHubEnvironmentByName { Mandatory, ValueFromPipelineByPropertyName )] - [Alias('Organization', 'User')] [string] $Owner, # The name of the repository without the .git extension. The name is not case sensitive. @@ -88,9 +87,7 @@ filter Get-GitHubEnvironmentByName { } try { Invoke-GitHubAPI @inputObject | ForEach-Object { - $environment = [GitHubEnvironment]::new($_.Response, $Owner, $Repository) - $environment.Url = "https://$($Context.HostName)/$Owner/$Repository/settings/environments/$($environment.ID)/edit" - $environment + [GitHubEnvironment]::new($_.Response, $Owner, $Repository, $Context) } } catch { return diff --git a/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 b/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 index 85d191c16..c4cd691bb 100644 --- a/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 +++ b/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 @@ -82,10 +82,8 @@ filter Get-GitHubEnvironmentList { } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response.environments | ForEach-Object { - $environment = [GitHubEnvironment]::new($_, $Owner, $Repository) - $environment.Url = "https://$($Context.HostName)/$Owner/$Repository/settings/environments/$($environment.ID)/edit" - $environment + foreach ($environment in $_.Response.environments) { + [GitHubEnvironment]::new($environment, $Owner, $Repository, $Context) } } } diff --git a/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 b/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 index 98ffe0674..60f8aee2f 100644 --- a/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 @@ -58,7 +58,9 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { [GitHubOrganization]::new($_, $Context.HostName) } + foreach ($organization in $_.Response) { + [GitHubOrganization]::new($organization, $Context) + } } } end { diff --git a/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 b/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 deleted file mode 100644 index d11b5aebe..000000000 --- a/src/functions/private/Organization/Get-GitHubMyOrganization.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -filter Get-GitHubMyOrganization { - <# - .SYNOPSIS - List organizations for the authenticated user - - .DESCRIPTION - List organizations for the authenticated user. - - **OAuth scope requirements** - - This only lists organizations that your authorization allows you to operate on - in some way (e.g., you can list teams with `read:org` scope, you can publicize your - organization membership with `user` scope, etc.). Therefore, this API requires at - least `user` or `read:org` scope. OAuth requests with insufficient scope receive a - `403 Forbidden` response. - - .EXAMPLE - Get-GitHubMyOrganization - - List organizations for the authenticated user. - - .OUTPUTS - GitHubOrganization - - .NOTES - [List organizations for the authenticated user](https://docs.github.com/rest/orgs/orgs#list-organizations-for-the-authenticated-user) - #> - [OutputType([GitHubOrganization])] - [CmdletBinding()] - param( - # The number of results per page (max 100). - [Parameter()] - [System.Nullable[int]] $PerPage, - - # The context to run the command in. Used to get the details for the API call. - # Can be either a string or a GitHubContext object. - [Parameter(Mandatory)] - [object] $Context - ) - - begin { - $stackPath = Get-PSCallStackPath - Write-Debug "[$stackPath] - Start" - Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT - } - - process { - $inputObject = @{ - Method = 'GET' - APIEndpoint = '/user/orgs' - PerPage = $PerPage - Context = $Context - } - - Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { [GitHubOrganization]::new($_, $Context.HostName) } - } - } - - end { - Write-Debug "[$stackPath] - End" - } -} diff --git a/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 b/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 index 03595108f..aee398ab2 100644 --- a/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 +++ b/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 @@ -56,7 +56,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - [GitHubOrganization]::new($_.Response, '') + [GitHubOrganization]::new($_.Response, $Context) } } end { diff --git a/src/functions/private/Organization/Get-GitHubOrganizationListForAuthUser.ps1 b/src/functions/private/Organization/Get-GitHubOrganizationListForAuthUser.ps1 new file mode 100644 index 000000000..a8024ee6b --- /dev/null +++ b/src/functions/private/Organization/Get-GitHubOrganizationListForAuthUser.ps1 @@ -0,0 +1,104 @@ +function Get-GitHubOrganizationListForAuthUser { + <# + .SYNOPSIS + Retrieves a list of all GitHub organizations for the authenticated user. + + .DESCRIPTION + This function retrieves detailed information about all GitHub organizations that the authenticated user belongs to, including their avatars, + creation dates, member counts, and other metadata. It returns an array of objects of type GitHubOrganization populated with this information. + + .EXAMPLE + Get-GitHubOrganizationListForAuthUser + + Output: + ```powershell + Name : MyOrganization + Login : my-org + URL : https://github.com/my-org + CreatedAt : 2022-01-01T00:00:00Z + + Name : Another Organization + Login : another-org + URL : https://github.com/another-org + CreatedAt : 2021-12-01T00:00:00Z + ``` + + Retrieves details about the GitHub organizations the authenticated user belongs to. + + .OUTPUTS + GitHubOrganization[] + + .NOTES + An array of objects containing detailed information about the GitHub organizations, including member info, URLs, and metadata. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', 'hasNextPage', Scope = 'Function', + Justification = 'Unknown issue with var scoping in blocks.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', 'after', Scope = 'Function', + Justification = 'Unknown issue with var scoping in blocks.' + )] + [OutputType([GitHubOrganization[]])] + [CmdletBinding()] + param( + # The number of results per page (max 100). + [Parameter()] + [System.Nullable[int]] $PerPage, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $hasNextPage = $false + $after = $null + $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context + + $graphQLFields = ([GitHubOrganization]::PropertyToGraphQLMap).Values + + do { + $organizationQuery = @{ + query = @" +query(`$perPage: Int!, `$after: String) { + viewer { + organizations(first: `$perPage, after: `$after) { + nodes { + $graphQLFields + } + pageInfo { + endCursor + hasNextPage + } + } + } +} +"@ + Variables = @{ + perPage = $perPageSetting + after = $after + } + Context = $Context + } + Invoke-GitHubGraphQLQuery @organizationQuery | ForEach-Object { + foreach ($organization in $_.viewer.organizations.nodes) { + [GitHubOrganization]::new($organization, $Context) + } + $hasNextPage = $_.viewer.organizations.pageInfo.hasNextPage + $after = $_.viewer.organizations.pageInfo.endCursor + } + } while ($hasNextPage) + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 b/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 index 6a8df5659..6cd3d6e9b 100644 --- a/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 @@ -55,8 +55,8 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - foreach ($org in $_.Response) { - [GitHubOrganization]::new($org, $Context.HostName) + foreach ($organization in $_.Response) { + [GitHubOrganization]::new($organization, $Context) } } } diff --git a/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 similarity index 94% rename from src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 rename to src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 index 0bce42cff..e614f7f10 100644 --- a/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 +++ b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 @@ -24,8 +24,6 @@ param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory)] - [Alias('Organization')] - [Alias('User')] [string] $Owner, # The name of the repository without the .git extension. The name is not case sensitive. @@ -34,7 +32,6 @@ # The unique identifier of the rule suite result. To get this ID, you can use GET /repos/ { owner }/ { repo }/rulesets/rule-suites for repositories and GET /orgs/ { org }/rulesets/rule-suites for organizations. [Parameter(Mandatory)] - [Alias('RuleSuiteId')] [int] $ID, # The context to run the command in. Used to get the details for the API call. @@ -66,5 +63,3 @@ Write-Debug "[$stackPath] - End" } } - -#SkipTest:FunctionTest:Will add a test for this function in a future PR diff --git a/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 similarity index 96% rename from src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 rename to src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 index d124a6b77..7843a405b 100644 --- a/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 +++ b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 @@ -32,8 +32,6 @@ param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory)] - [Alias('Organization')] - [Alias('User')] [string] $Owner, # The name of the repository without the .git extension. The name is not case sensitive. @@ -104,5 +102,3 @@ Write-Debug "[$stackPath] - End" } } - -#SkipTest:FunctionTest:Will add a test for this function in a future PR diff --git a/src/functions/private/Users/Get-GitHubAllUser.ps1 b/src/functions/private/Users/Get-GitHubAllUser.ps1 index 43d57fc63..ea8233a2e 100644 --- a/src/functions/private/Users/Get-GitHubAllUser.ps1 +++ b/src/functions/private/Users/Get-GitHubAllUser.ps1 @@ -58,13 +58,13 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { - if ($_.type -eq 'Organization') { - [GitHubOrganization]::New($_, '') - } elseif ($_.type -eq 'User') { - [GitHubUser]::New($_) + foreach ($account in $_.Response) { + if ($account.type -eq 'Organization') { + [GitHubOrganization]::New($account, $Context) + } elseif ($account.type -eq 'User') { + [GitHubUser]::New($account) } else { - [GitHubOwner]::New($_) + [GitHubOwner]::New($account) } } } diff --git a/src/functions/private/Users/Get-GitHubMyUser.ps1 b/src/functions/private/Users/Get-GitHubMyUser.ps1 index 7526a7837..6141d5043 100644 --- a/src/functions/private/Users/Get-GitHubMyUser.ps1 +++ b/src/functions/private/Users/Get-GitHubMyUser.ps1 @@ -44,7 +44,7 @@ Invoke-GitHubAPI @inputObject | ForEach-Object { if ($_.Response.type -eq 'Organization') { - [GitHubOrganization]::New($_.Response, $Context.HostName) + [GitHubOrganization]::New($_.Response, $Context) } elseif ($_.Response.type -eq 'User') { [GitHubUser]::New($_.Response) } else { diff --git a/src/functions/private/Users/Get-GitHubUserByName.ps1 b/src/functions/private/Users/Get-GitHubUserByName.ps1 index 701bca251..880b63e55 100644 --- a/src/functions/private/Users/Get-GitHubUserByName.ps1 +++ b/src/functions/private/Users/Get-GitHubUserByName.ps1 @@ -62,7 +62,7 @@ try { Invoke-GitHubAPI @inputObject | ForEach-Object { if ($_.Response.type -eq 'Organization') { - [GitHubOrganization]::New($_.Response, $Context.HostName) + [GitHubOrganization]::New($_.Response, $Context) } elseif ($_.Response.type -eq 'User') { [GitHubUser]::New($_.Response) } else { diff --git a/src/functions/public/Auth/Connect-GitHubApp.ps1 b/src/functions/public/Auth/Connect-GitHubApp.ps1 index c74caafba..1994c5082 100644 --- a/src/functions/public/Auth/Connect-GitHubApp.ps1 +++ b/src/functions/public/Auth/Connect-GitHubApp.ps1 @@ -122,7 +122,7 @@ $selectedInstallations | ForEach-Object { $installation = $_ Write-Verbose "Processing installation [$($installation.Target.Name)] [$($installation.id)]" - $token = New-GitHubAppInstallationAccessToken -Context $Context -InstallationID $installation.id + $token = New-GitHubAppInstallationAccessToken -Context $Context -ID $installation.id $contextParams = @{ AuthType = [string]'IAT' diff --git a/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 b/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 index 079a3a89b..20493743e 100644 --- a/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 +++ b/src/functions/public/Enterprise/Get-GitHubEnterprise.ps1 @@ -1,12 +1,30 @@ function Get-GitHubEnterprise { <# .SYNOPSIS - Retrieves details about a GitHub Enterprise instance by name (slug). + Retrieves GitHub Enterprise instance details for the authenticated user. .DESCRIPTION - This function retrieves detailed information about a GitHub Enterprise instance, including its avatar, billing details, storage usage, - creation date, and other metadata based on the provided name (slug). It returns an object of type GitHubEnterprise populated with this - information. + Retrieves detailed information about GitHub Enterprise instances available to the authenticated user. + By default, the command lists all accessible instances, including metadata such as the enterprise name, slug, URL, and creation date. If a + specific enterprise name is provided, details about that single instance are returned. + + .EXAMPLE + Get-GitHubEnterprise + + Output: + ```powershell + Name : My Enterprise + Slug : my-enterprise + URL : https://github.com/enterprises/my-enterprise + CreatedAt : 2022-01-01T00:00:00Z + + Name : Another Enterprise + Slug : another-enterprise + URL : https://github.com/enterprises/another-enterprise + CreatedAt : 2022-01-01T00:00:00Z + ``` + + Retrieves details about all GitHub Enterprise instances for the user. .EXAMPLE Get-GitHubEnterprise -Name 'my-enterprise' @@ -17,7 +35,6 @@ Slug : my-enterprise URL : https://github.com/enterprises/my-enterprise CreatedAt : 2022-01-01T00:00:00Z - ViewerIsAdmin : True ``` Retrieves details about the GitHub Enterprise instance named 'my-enterprise'. @@ -32,10 +49,10 @@ https://psmodule.io/GitHub/Functions/Enterprise/Get-GitHubEnterprise/ #> [OutputType([GitHubEnterprise])] - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'List enterprises for the authenticated user')] param( # The name (slug) of the GitHub Enterprise instance to retrieve. - [Parameter(Mandatory)] + [Parameter(Mandatory, ParameterSetName = 'Get enterprise by name')] [Alias('Slug')] [string] $Name, @@ -53,49 +70,16 @@ } process { - $enterpriseQuery = @{ - query = @' -query($Slug: String!) { - enterprise(slug: $Slug) { - avatarUrl - billingEmail - billingInfo { - allLicensableUsersCount - assetPacks - bandwidthQuota - bandwidthUsage - bandwidthUsagePercentage - storageQuota - storageUsage - storageUsagePercentage - totalAvailableLicenses - totalLicenses - } - createdAt - databaseId - description - descriptionHTML - id - location - name - readme - readmeHTML - resourcePath - slug - updatedAt - url - viewerIsAdmin - websiteUrl - } -} -'@ - Variables = @{ - Slug = $Name + Write-Debug "ParameterSet: $($PSCmdlet.ParameterSetName)" + switch ($PSCmdlet.ParameterSetName) { + 'Get enterprise by name' { + Get-GitHubEnterpriseByName -Name $Name -Context $Context + break + } + default { + Get-GitHubEnterpriseList -Context $Context } - Context = $Context } - $enterpriseResult = Invoke-GitHubGraphQLQuery @enterpriseQuery - [GitHubEnterprise]::new($enterpriseResult.enterprise) } end { diff --git a/src/functions/public/Environments/Set-GitHubEnvironment.ps1 b/src/functions/public/Environments/Set-GitHubEnvironment.ps1 index 65c0b326c..b048f185e 100644 --- a/src/functions/public/Environments/Set-GitHubEnvironment.ps1 +++ b/src/functions/public/Environments/Set-GitHubEnvironment.ps1 @@ -182,9 +182,7 @@ if ($PSCmdlet.ShouldProcess("Environment [$Owner/$Repository/$Name]", 'Set')) { Invoke-GitHubAPI @inputObject | ForEach-Object { - $environment = [GitHubEnvironment]::new($_.Response, $Owner, $Repository) - $environment.Url = "https://$($Context.HostName)/$Owner/$Repository/settings/environments/$($environment.ID)/edit" - $environment + [GitHubEnvironment]::new($_.Response, $Owner, $Repository, $Context) } } } diff --git a/src/functions/public/Organization/Get-GitHubOrganization.ps1 b/src/functions/public/Organization/Get-GitHubOrganization.ps1 index cd490cd5d..526e66e74 100644 --- a/src/functions/public/Organization/Get-GitHubOrganization.ps1 +++ b/src/functions/public/Organization/Get-GitHubOrganization.ps1 @@ -114,7 +114,7 @@ Get-GitHubAllOrganization -Since $Since -PerPage $PerPage -Context $Context } 'List all organizations for the authenticated user' { - Get-GitHubMyOrganization -PerPage $PerPage -Context $Context + Get-GitHubOrganizationListForAuthUser -PerPage $PerPage -Context $Context } default { Write-Error "Invalid parameter set name: $($PSCmdlet.ParameterSetName)" diff --git a/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 b/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 index 75e9bc920..2354b1fb0 100644 --- a/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 +++ b/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 @@ -67,7 +67,9 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - $_.Response | ForEach-Object { [GitHubUser]::new($_) } + foreach ($user in $_.Response) { + [GitHubUser]::new($user) + } } } diff --git a/src/functions/public/Organization/Update-GitHubOrganization.ps1 b/src/functions/public/Organization/Update-GitHubOrganization.ps1 index bfea406da..9095cf593 100644 --- a/src/functions/public/Organization/Update-GitHubOrganization.ps1 +++ b/src/functions/public/Organization/Update-GitHubOrganization.ps1 @@ -8,9 +8,9 @@ profile and member privileges. .EXAMPLE - Update-GitHubOrganization -Organization 'GitHub' -Blog 'https://github.blog' + Update-GitHubOrganization -Organization 'GitHub' -Description 'The official GitHub organization.' - Sets the blog URL for the organization 'GitHub' to ''. + Sets the description for the organization 'GitHub' to 'The official GitHub organization.'. .EXAMPLE $param = @{ @@ -134,9 +134,9 @@ [Parameter(ValueFromPipelineByPropertyName)] [bool] $WebCommitSignoffRequired, - # Path to the organization's blog. + # Path to the organization's site. [Parameter(ValueFromPipelineByPropertyName)] - [string] $Blog, + [string] $Website, # Whether secret scanning push protection is automatically enabled for new repositories. # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for @@ -171,7 +171,7 @@ $body = @{ name = $NewName billing_email = $BillingEmail - blog = $Blog + blog = $Website company = $Company description = $Description email = $Email @@ -204,7 +204,7 @@ if ($PSCmdlet.ShouldProcess("organization [$Name]", 'Set')) { Invoke-GitHubAPI @inputObject | ForEach-Object { - [GitHubOrganization]::new($_.Response, '') + [GitHubOrganization]::new($_.Response, $Context) } } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 index e5356b44d..c26043b60 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 @@ -19,7 +19,6 @@ .LINK https://psmodule.io/GitHub/Functions/Repositories/Repositories/Get-GitHubRepositorySecurityFix #> - [Alias('Get-GitHubRepoSecurityFixes')] [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')] param( diff --git a/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuite.ps1 b/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuite.ps1 index d24ceb1e3..741f9e9b3 100644 --- a/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuite.ps1 +++ b/src/functions/public/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuite.ps1 @@ -39,7 +39,6 @@ param( # The account owner of the repository. The name is not case sensitive. [Parameter()] - [Alias('org')] [string] $Owner, # The name of the repository without the .git extension. The name is not case sensitive. diff --git a/src/functions/public/Users/Update-GitHubUser.ps1 b/src/functions/public/Users/Update-GitHubUser.ps1 index 69af9e3d2..7338bb66c 100644 --- a/src/functions/public/Users/Update-GitHubUser.ps1 +++ b/src/functions/public/Users/Update-GitHubUser.ps1 @@ -19,9 +19,9 @@ Update the authenticated user's location to 'San Francisco' .EXAMPLE - Update-GitHubUser -Hireable $true -Bio 'I love programming' + Update-GitHubUser -Hireable $true -Description 'I love programming' - Update the authenticated user's hiring availability to 'true' and their biography to 'I love programming' + Update the authenticated user's hiring availability to 'true' and their description to 'I love programming' .NOTES [Update the authenticated user](https://docs.github.com/rest/users/users#update-the-authenticated-user) @@ -40,9 +40,10 @@ [Parameter()] [string] $Email, - # The new blog URL of the user. + # The new site for the user. [Parameter()] - [string] $Blog, + [Alias('Blog')] + [string] $Website, # The new Twitter username of the user. [Parameter()] @@ -62,7 +63,8 @@ # The new short biography of the user. [Parameter()] - [string] $Bio, + [Alias('Bio')] + [string] $Description, # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. @@ -81,12 +83,12 @@ $body = @{ name = $DisplayName email = $Email - blog = $Blog + blog = $Website twitter_username = $TwitterUsername company = $Company location = $Location hireable = $Hireable - bio = $Bio + bio = $Description } $body | Remove-HashtableEntry -NullOrEmptyValues diff --git a/src/types/GitHubUser.Types.ps1xml b/src/types/GitHubUser.Types.ps1xml index f81e6433f..275d10688 100644 --- a/src/types/GitHubUser.Types.ps1xml +++ b/src/types/GitHubUser.Types.ps1xml @@ -7,6 +7,14 @@ User $this.Name + + Bio + $this.Description + + + Blog + $this.Website +
diff --git a/tests/Enterprise.ps1 b/tests/Enterprise.Tests.ps1 similarity index 66% rename from tests/Enterprise.ps1 rename to tests/Enterprise.Tests.ps1 index 9a4760271..b6b7a73dd 100644 --- a/tests/Enterprise.ps1 +++ b/tests/Enterprise.Tests.ps1 @@ -33,11 +33,9 @@ Describe 'Template' { Write-Host ($context | Format-List | Out-String) } if ($AuthType -eq 'APP') { - It 'Connect-GitHubApp - Connects as a GitHub App to ' { + LogGroup 'Context - Installation' { $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent - LogGroup 'Context - Installation' { - Write-Host ($context | Format-List | Out-String) - } + Write-Host ($context | Format-List | Out-String) } } } @@ -46,7 +44,7 @@ Describe 'Template' { Write-Host ('-' * 60) } - It 'Get-GitHubEnterprise - Can get info about an enterprise' -Skip:($OwnerType -notlike 'enterprise') { + It 'Get-GitHubEnterprise - Can get info about an enterprise' -Skip:($OwnerType -ne 'enterprise') { $enterprise = Get-GitHubEnterprise -Name $Owner LogGroup 'Enterprise' { Write-Host ($enterprise | Select-Object * | Out-String) @@ -58,29 +56,15 @@ Describe 'Template' { $enterprise.ID | Should -Be 15567 $enterprise.NodeID | Should -Be 'E_kgDNPM8' $enterprise.AvatarUrl | Should -Be 'https://avatars.githubusercontent.com/b/15567?v=4' - $enterprise.BillingEmail | Should -Be 'marstor@hotmail.com' $enterprise.Url | Should -Be 'https://github.com/enterprises/msx' $enterprise.Type | Should -Be 'Enterprise' - $enterprise.BillingInfo | Should -BeOfType 'GitHubBillingInfo' - $enterprise.BillingInfo.AllLicensableUsersCount | Should -Be 1 - $enterprise.BillingInfo.AssetPacks | Should -Be 0 - $enterprise.BillingInfo.BandwidthQuota | Should -Be 5 - $enterprise.BillingInfo.BandwidthUsage | Should -Be 0 - $enterprise.BillingInfo.BandwidthUsagePercentage | Should -Be 0 - $enterprise.BillingInfo.StorageQuota | Should -Be 5 - $enterprise.BillingInfo.StorageUsage | Should -Be 0 - $enterprise.BillingInfo.StorageUsagePercentage | Should -Be 0 - $enterprise.BillingInfo.TotalAvailableLicenses | Should -Be 0 - $enterprise.BillingInfo.TotalLicenses | Should -Be 1 $enterprise.Readme | Should -Be 'This is a test' $enterprise.ReadmeHTML | Should -Be '

This is a test

' $enterprise.CreatedAt | Should -BeOfType 'DateTime' - $enterprise.CreatedAt | Should -Be (Get-Date '18.09.2022 19:53:09') $enterprise.UpdatedAt | Should -BeOfType 'DateTime' $enterprise.Description | Should -Be 'This is the description' - $enterprise.DescriptionHTML | Should -Be '
This is the description
' $enterprise.Location | Should -Be 'Oslo, Norway' - $enterprise.Blog | Should -Be 'https://msx.no' + $enterprise.Website | Should -Be 'https://msx.no' } } } diff --git a/tests/Organizations.Tests.ps1 b/tests/Organizations.Tests.ps1 index 32ddb2b28..4136b6b53 100644 --- a/tests/Organizations.Tests.ps1 +++ b/tests/Organizations.Tests.ps1 @@ -94,7 +94,7 @@ Describe 'Organizations' { { Update-GitHubOrganization -Name $owner -Description 'Test Organization' } | Should -Not -Throw { Update-GitHubOrganization -Name $owner -DefaultRepositoryPermission read } | Should -Not -Throw { Update-GitHubOrganization -Name $owner -MembersCanCreateRepositories $true } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -Blog 'https://psmodule.io' } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -Website 'https://psmodule.io' } | Should -Not -Throw } } diff --git a/tests/Users.Tests.ps1 b/tests/Users.Tests.ps1 index 5dcd0ec18..f4cb7cc32 100644 --- a/tests/Users.Tests.ps1 +++ b/tests/Users.Tests.ps1 @@ -54,17 +54,21 @@ Describe 'Users' { $user = Get-GitHubUser { Update-GitHubUser -DisplayName 'Octocat' } | Should -Not -Throw { Update-GitHubUser -Blog 'https://psmodule.io' } | Should -Not -Throw + { Update-GitHubUser -Website 'https://psmodule.io' } | Should -Not -Throw { Update-GitHubUser -TwitterUsername 'PSModule' } | Should -Not -Throw { Update-GitHubUser -Company 'PSModule' } | Should -Not -Throw { Update-GitHubUser -Location 'USA' } | Should -Not -Throw { Update-GitHubUser -Bio 'I love programming' } | Should -Not -Throw + { Update-GitHubUser -Description 'I love programming' } | Should -Not -Throw $tmpUser = Get-GitHubUser $tmpUser.DisplayName | Should -Be 'Octocat' $tmpUser.Blog | Should -Be 'https://psmodule.io' + $tmpUser.Website | Should -Be 'https://psmodule.io' $tmpUser.TwitterUsername | Should -Be 'PSModule' $tmpUser.Company | Should -Be 'PSModule' $tmpUser.Location | Should -Be 'USA' $tmpUser.Bio | Should -Be 'I love programming' + $tmpUser.Description | Should -Be 'I love programming' # Flaky tests # { Update-GitHubUser -Hireable $true } | Should -Not -Throw From c15c9f4f708729fa5837e5902b9219118fa2c413 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 7 Jul 2025 22:15:58 +0200 Subject: [PATCH 09/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20`New-GitH?= =?UTF-8?q?ubOrganization`=20function=20(#462)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces several new features and improvements to the PowerShell module for managing GitHub organizations and apps. Key changes include new functions for creating and managing organizations, enhancements to app installation workflows, and updates to testing coverage for these functionalities. - Fixes #459 ### New and updated functions * Added a `New-GitHubOrganization` function to create GitHub organizations within a specified enterprise. This includes support for specifying owners, billing emails, and enterprise contexts. * Updated the `Remove-GitHubOrganization` function to support removing multiple organizations via an array input parameter, improving flexibility. ### Improvements to App Installation * Modified the `Install-GitHubAppOnEnterpriseOrganization` function to validate repository selection values case-insensitively and return strongly-typed `GitHubAppInstallation` objects. ### Updates to Organization Properties * Corrected property mappings in the `GitHubOrganization` class to ensure accurate handling of `RequireWebCommitSignoff`. ### Testing Enhancements * Added new tests for organization creation, updates, app installation, and removal, improving validation for enterprise workflows. ### Debugging Improvements * Updated `Invoke-GitHubAPI` to include detailed context information in error messages, aiding debugging efforts. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- examples/Organizations/Organization.ps1 | 41 +++++++ .../Owner/GitHubOwner/GitHubOrganization.ps1 | 2 +- ...tall-GitHubAppOnEnterpriseOrganization.ps1 | 8 +- src/functions/public/API/Invoke-GitHubAPI.ps1 | 4 + .../Organization/New-GitHubOrganization.ps1 | 88 ++++++++++++++ .../Remove-GitHubOrganization.ps1 | 42 ++++--- tests/Organizations.Tests.ps1 | 115 +++++++++++++----- 7 files changed, 249 insertions(+), 51 deletions(-) create mode 100644 examples/Organizations/Organization.ps1 create mode 100644 src/functions/public/Organization/New-GitHubOrganization.ps1 diff --git a/examples/Organizations/Organization.ps1 b/examples/Organizations/Organization.ps1 new file mode 100644 index 000000000..4e4fcfbe3 --- /dev/null +++ b/examples/Organizations/Organization.ps1 @@ -0,0 +1,41 @@ +$orgParam = @{ + Enterprise = 'msx' + Name = 'Marius-Test7' + Owner = 'GitHub-Automation' + BillingEmail = 'post@msx.no' +} +$org = New-GitHubOrganization @orgParam + +$installAppParam = @{ + Enterprise = 'msx' + Organization = $org.login + ClientID = (Get-GitHubContext).ClientID + RepositorySelection = 'all' +} +Install-GitHubApp @installAppParam + +$updateOrgParam = @{ + Name = $org.login + Description = 'Test organization created by PowerShell script' + Location = 'Oslo, Norway' + BillingEmail = 'post@msx.no' + Company = 'MSX AS' + Email = 'info@msx.no' + Blog = 'https://msx.no/blog' + TwitterUsername = 'msx_no' + HasOrganizationProjects = $true + DefaultRepositoryPermission = 'read' + MembersCanCreateRepositories = $true + MembersCanCreatePublicRepositories = $true + MembersCanCreatePrivateRepositories = $true + MembersCanCreateInternalRepositories = $true + MembersCanCreatePages = $true + MembersCanCreatePublicPages = $true + MembersCanCreatePrivatePages = $true + MembersCanForkPrivateRepositories = $true + WebCommitSignoffRequired = $false + SecretScanningPushProtectionEnabledForNewRepositories = $true + SecretScanningPushProtectionCustomLinkEnabled = $false + SecretScanningPushProtectionCustomLink = '' +} +Update-GitHubOrganization @updateOrgParam diff --git a/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 b/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 index 48528dba2..a99927110 100644 --- a/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 +++ b/src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1 @@ -225,7 +225,7 @@ $this.MembersCanInviteCollaborators = $Object.members_can_invite_collaborators $this.MembersCanCreatePages = $Object.members_can_create_pages $this.MembersCanForkPrivateRepositories = $Object.members_can_fork_private_repositories ?? $Object.membersCanForkPrivateRepositories - $this.RequireWebCommitSignoff = $Object.web_commit_signoff_required ?? $Object.requiresTwoFactorAuthentication + $this.RequireWebCommitSignoff = $Object.web_commit_signoff_required ?? $Object.webCommitSignoffRequired $this.DeployKeysEnabledForRepositories = $Object.deploy_keys_enabled_for_repositories $this.MembersCanCreatePublicPages = $Object.members_can_create_public_pages $this.MembersCanCreatePrivatePages = $Object.members_can_create_private_pages diff --git a/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 index b66c98e66..d8d847476 100644 --- a/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 @@ -11,6 +11,7 @@ .EXAMPLE Install-GitHubAppOnEnterpriseOrganization -Enterprise 'msx' -Organization 'org' -ClientID '123456' #> + [OutputType([GitHubAppInstallation])] [CmdletBinding()] param( # The enterprise slug or ID. @@ -29,7 +30,7 @@ # - all - all repositories that the authenticated GitHub App installation can access. # - selected - select specific repositories. [Parameter(Mandatory)] - [ValidateSet('all', 'selected')] + [ValidateSet('All', 'Selected')] [string] $RepositorySelection, # The names of the repositories to which the installation will be granted access. @@ -49,6 +50,9 @@ } process { + if ($RepositorySelection) { + $RepositorySelection = $RepositorySelection.ToLower() + } $body = @{ client_id = $ClientID repository_selection = $RepositorySelection @@ -64,7 +68,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + [GitHubAppInstallation]::new($_.Response) } } diff --git a/src/functions/public/API/Invoke-GitHubAPI.ps1 b/src/functions/public/API/Invoke-GitHubAPI.ps1 index 9261893b5..2c4d9279b 100644 --- a/src/functions/public/API/Invoke-GitHubAPI.ps1 +++ b/src/functions/public/API/Invoke-GitHubAPI.ps1 @@ -315,6 +315,10 @@ function Invoke-GitHubAPI { } $exception = @" + +---------------------------------- +Context: +$($Context | Format-List | Out-String) ---------------------------------- Request: $([pscustomobject]$APICall | Select-Object -ExcludeProperty Body, Headers | Format-List | Out-String) diff --git a/src/functions/public/Organization/New-GitHubOrganization.ps1 b/src/functions/public/Organization/New-GitHubOrganization.ps1 new file mode 100644 index 000000000..7279e9358 --- /dev/null +++ b/src/functions/public/Organization/New-GitHubOrganization.ps1 @@ -0,0 +1,88 @@ +function New-GitHubOrganization { + <# + .SYNOPSIS + Creates a new GitHub organization within a specified enterprise. + + .DESCRIPTION + This function creates a new GitHub organization within the specified enterprise. + + .EXAMPLE + New-GitHubOrganization -Enterprise 'my-enterprise' -Name 'my-org' -Owner 'user1' -BillingEmail 'billing@example.com' + + .OUTPUTS + GitHubOrganization + + .LINK + https://psmodule.io/GitHub/Functions/Organization/New-GitHubOrganization/ + #> + [OutputType([GitHubOrganization])] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] + param( + # The name of the enterprise to create the organization in. + [Parameter()] + [string]$Enterprise, + + # The name of the organization to create. + [Parameter(Mandatory)] + [string]$Name, + + # The owners of the organization. This should be a list of GitHub usernames. + [Parameter(Mandatory)] + [string[]]$Owner, + + # The billing email for the organization. + [Parameter()] + [string]$BillingEmail, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $enterpriseObject = Get-GitHubEnterprise -Name $Enterprise -Context $Context + Write-Verbose "Creating organization in enterprise: $($enterpriseObject.Name)" + $graphQLFields = ([GitHubOrganization]::PropertyToGraphQLMap).Values + + $inputParams = @{ + adminLogins = $Owner + billingEmail = $BillingEmail + enterpriseId = $enterpriseObject.NodeID + login = $Name + profileName = $Name + } + + $updateGraphQLInputs = @{ + Query = @" +mutation(`$input:CreateEnterpriseOrganizationInput!) { + createEnterpriseOrganization(input:`$input) { + organization { + $graphQLFields + } + } +} +"@ + Variables = @{ + input = $inputParams + } + Context = $Context + } + if ($PSCmdlet.ShouldProcess("Creating organization '$Name' in enterprise '$Enterprise'")) { + $orgresult = Invoke-GitHubGraphQLQuery @updateGraphQLInputs + [GitHubOrganization]::new($orgresult.createEnterpriseOrganization.organization, $Context) + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} + diff --git a/src/functions/public/Organization/Remove-GitHubOrganization.ps1 b/src/functions/public/Organization/Remove-GitHubOrganization.ps1 index 0d9f3c310..8f31b57c3 100644 --- a/src/functions/public/Organization/Remove-GitHubOrganization.ps1 +++ b/src/functions/public/Organization/Remove-GitHubOrganization.ps1 @@ -24,16 +24,16 @@ https://psmodule.io/GitHub/Functions/Organization/Remove-GitHubOrganization #> [OutputType([void])] - [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] + [CmdletBinding(DefaultParameterSetName = 'Remove an organization', SupportsShouldProcess, ConfirmImpact = 'High')] param( # The organization name. The name is not case sensitive. - [Parameter( - Mandatory, - ValueFromPipeline, - ValueFromPipelineByPropertyName - )] + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [string] $Name, + # The input object to process. Can be a single or an array of GitHubOrganization objects. + [Parameter(Mandatory, ParameterSetName = 'ArrayInput', ValueFromPipeline)] + [GitHubOrganization[]] $InputObject, + # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. [Parameter()] @@ -48,14 +48,28 @@ } process { - $inputObject = @{ - Method = 'DELETE' - APIEndpoint = "/orgs/$Name" - Context = $Context - } + switch ($PSCmdlet.ParameterSetName) { + 'ArrayInput' { + foreach ($item in $InputObject) { + $params = @{ + Name = $item.Name + Context = $Context + } + Remove-GitHubOrganization @params + } + break + } + default { + $apiParams = @{ + Method = 'DELETE' + APIEndpoint = "/orgs/$Name" + Context = $Context + } - if ($PSCmdlet.ShouldProcess("organization [$Name]", 'DELETE')) { - $null = Invoke-GitHubAPI @inputObject + if ($PSCmdlet.ShouldProcess("organization [$Name]", 'Delete')) { + $null = Invoke-GitHubAPI @apiParams + } + } } } @@ -63,5 +77,3 @@ Write-Debug "[$stackPath] - End" } } - -#SkipTest:FunctionTest:Will add a test for this function in a future PR diff --git a/tests/Organizations.Tests.ps1 b/tests/Organizations.Tests.ps1 index 4136b6b53..7d1740e5c 100644 --- a/tests/Organizations.Tests.ps1 +++ b/tests/Organizations.Tests.ps1 @@ -20,7 +20,9 @@ param() BeforeAll { - # DEFAULTS ACCROSS ALL TESTS + $testName = 'MsxOrgTests' + $os = $env:RUNNER_OS + $number = Get-Random } Describe 'Organizations' { @@ -32,25 +34,21 @@ Describe 'Organizations' { LogGroup 'Context' { Write-Host ($context | Select-Object * | Out-String) } + $orgPrefix = "$testName-$os-" + $orgName = "$orgPrefix$number" + + if ($AuthType -eq 'APP') { + $installationContext = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent + LogGroup 'Context - Installation' { + Write-Host ($installationContext | Select-Object * | Out-String) + } + } } AfterAll { Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent Write-Host ('-' * 60) } - # Tests for APP goes here - if ($AuthType -eq 'APP') { - It 'Connect-GitHubApp - Connects as a GitHub App to ' { - $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent - LogGroup 'Context' { - Write-Host ($context | Select-Object * | Out-String) - } - } - } - - # Tests for runners goes here - if ($Type -eq 'GitHub Actions') {} - It "Get-GitHubOrganization - Gets a specific organization 'PSModule'" { $organization = Get-GitHubOrganization -Name 'PSModule' LogGroup 'Organization' { @@ -58,6 +56,7 @@ Describe 'Organizations' { } $organization | Should -Not -BeNullOrEmpty } + It "Get-GitHubOrganization - List public organizations for the user 'psmodule-user'" { $organizations = Get-GitHubOrganization -Username 'psmodule-user' LogGroup 'Organization' { @@ -65,6 +64,7 @@ Describe 'Organizations' { } $organizations | Should -Not -BeNullOrEmpty } + It 'Get-GitHubOrganizationMember - Gets the members of a specific organization' -Skip:($OwnerType -in ('user', 'enterprise')) { $members = Get-GitHubOrganizationMember -Organization $owner LogGroup 'Members' { @@ -73,29 +73,78 @@ Describe 'Organizations' { $members | Should -Not -BeNullOrEmpty } - # Tests for IAT UAT and PAT goes here - It 'Get-GitHubOrganization - Gets the organizations for the authenticated user' -Skip:($OwnerType -notin ('user')) { + It 'Get-GitHubOrganization - Gets the organizations for the authenticated user' -Skip:($Type -eq 'GitHub Actions') { + $orgs = Get-GitHubOrganization | Where-Object { $_.Name -like "$orgPrefix*" } | Out-String + LogGroup 'Organizations' { + $orgs | Format-Table -AutoSize | Out-String + } { Get-GitHubOrganization } | Should -Not -Throw } - if ($OwnerType -eq 'organization' -and $Type -ne 'GitHub Actions') { - It 'Update-GitHubOrganization - Sets the organization configuration' { - { Update-GitHubOrganization -Name $owner -Company 'ABC' } | Should -Not -Throw - { - $email = (New-Guid).Guid + '@psmodule.io' - Update-GitHubOrganization -Name $owner -BillingEmail $email - } | Should -Not -Throw - { - $email = (New-Guid).Guid + '@psmodule.io' - Update-GitHubOrganization -Name $owner -Email $email - } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -TwitterUsername 'PSModule' } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -Location 'USA' } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -Description 'Test Organization' } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -DefaultRepositoryPermission read } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -MembersCanCreateRepositories $true } | Should -Not -Throw - { Update-GitHubOrganization -Name $owner -Website 'https://psmodule.io' } | Should -Not -Throw + It 'Update-GitHubOrganization - Sets the organization configuration' -Skip:($OwnerType -ne 'organization' -or $Type -eq 'GitHub Actions') { + { Update-GitHubOrganization -Name $owner -Company 'ABC' } | Should -Not -Throw + { + $email = (New-Guid).Guid + '@psmodule.io' + Update-GitHubOrganization -Name $owner -BillingEmail $email + } | Should -Not -Throw + { + $email = (New-Guid).Guid + '@psmodule.io' + Update-GitHubOrganization -Name $owner -Email $email + } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -TwitterUsername 'PSModule' } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -Location 'USA' } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -Description 'Test Organization' } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -DefaultRepositoryPermission read } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -MembersCanCreateRepositories $true } | Should -Not -Throw + { Update-GitHubOrganization -Name $owner -Website 'https://psmodule.io' } | Should -Not -Throw + } + + It 'New-GitHubOrganization - Creates a new organization' -Skip:($OwnerType -ne 'enterprise') { + $orgParam = @{ + Enterprise = 'msx' + Name = $orgName + Owner = 'MariusStorhaug' + BillingEmail = 'post@msx.no' + } + LogGroup 'Organization' { + $org = New-GitHubOrganization @orgParam + Write-Host ($org | Select-Object * | Out-String) + } + } + + It 'Update-GitHubOrganization - Updates the organization location using enterprise installation' -Skip:($OwnerType -ne 'enterprise') { + { Update-GitHubOrganization -Name $orgName -Location 'New Location' } | Should -Throw + } + + It 'Remove-GitHubOrganization - Removes an organization using enterprise installation' -Skip:($OwnerType -ne 'enterprise') { + { Remove-GitHubOrganization -Name $orgName -Confirm:$false } | Should -Throw + } + + It 'Install-GitHubApp - Installs a GitHub App to an organization' -Skip:($OwnerType -ne 'enterprise') { + $installation = Install-GitHubApp -Enterprise $owner -Organization $orgName -ClientID $installationContext.ClientID -RepositorySelection 'all' + LogGroup 'Installed App' { + Write-Host ($installation | Select-Object * | Out-String) + } + $installation | Should -Not -BeNullOrEmpty + $installation | Should -BeOfType 'GitHubAppInstallation' + } + + It 'Connect-GitHubApp - Connects as a GitHub App to the organization' -Skip:($OwnerType -ne 'enterprise') { + $orgContext = Connect-GitHubApp -Organization $orgName -Context $context -PassThru -Silent + LogGroup 'Context' { + Write-Host ($orgContext | Select-Object * | Out-String) } + $orgContext | Should -Not -BeNullOrEmpty + } + + It 'Update-GitHubOrganization - Updates the organization location using organization installation' -Skip:($OwnerType -ne 'enterprise') { + $orgContext = Connect-GitHubApp -Organization $orgName -Context $context -PassThru -Silent + Update-GitHubOrganization -Name $orgName -Location 'New Location' -Context $orgContext + } + + It 'Remove-GitHubOrganization - Removes an organization using organization installation' -Skip:($OwnerType -ne 'enterprise') { + $orgContext = Connect-GitHubApp -Organization $orgName -Context $context -PassThru -Silent + Remove-GitHubOrganization -Name $orgName -Confirm:$false -Context $orgContext } Context 'Invitations' -Skip:($Owner -notin 'psmodule-test-org', 'psmodule-test-org2') { From c593843d460a8a34b99e5cc4d980fb5dea8ba078 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Jul 2025 10:33:52 +0200 Subject: [PATCH 10/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20support?= =?UTF-8?q?=20for=20US=20stamp=20in=20GitHub=20status=20functions=20(#463)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request adds support for the `US` stamp to various GitHub status-related scripts and updates the corresponding test cases. The changes ensure that the `US` stamp is included in parameter validation, base URLs, and test coverage. ### Updates to parameter validation: - Added `US` to the `ValidateSet` for the `$Stamp` parameter. * `Get-GitHubScheduledMaintenance` * `Get-GitHubStatus.ps1` * `Get-GitHubStatusComponent` * `Get-GitHubStatusIncident` ### Updates to base URLs * Added the base URL for the `US` stamp (`https://us.githubstatus.com`). ### Updates to test coverage: * Included `US` in the 'Status' test cases to ensure proper validation and functionality for the new stamp. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/functions/public/Status/Get-GitHubScheduledMaintenance.ps1 | 2 +- src/functions/public/Status/Get-GitHubStatus.ps1 | 2 +- src/functions/public/Status/Get-GitHubStatusComponent.ps1 | 2 +- src/functions/public/Status/Get-GitHubStatusIncident.ps1 | 2 +- src/variables/private/StatusBaseURL.ps1 | 1 + tests/GitHub.Tests.ps1 | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/functions/public/Status/Get-GitHubScheduledMaintenance.ps1 b/src/functions/public/Status/Get-GitHubScheduledMaintenance.ps1 index a86dae724..df799f233 100644 --- a/src/functions/public/Status/Get-GitHubScheduledMaintenance.ps1 +++ b/src/functions/public/Status/Get-GitHubScheduledMaintenance.ps1 @@ -48,7 +48,7 @@ # The stamp to check status for. [Parameter()] - [ValidateSet('Public', 'Europe', 'Australia')] + [ValidateSet('Public', 'Europe', 'Australia', 'US')] [string] $Stamp = 'Public' ) diff --git a/src/functions/public/Status/Get-GitHubStatus.ps1 b/src/functions/public/Status/Get-GitHubStatus.ps1 index e507ad48a..8a0072f1b 100644 --- a/src/functions/public/Status/Get-GitHubStatus.ps1 +++ b/src/functions/public/Status/Get-GitHubStatus.ps1 @@ -38,7 +38,7 @@ # The stamp to check status for. [Parameter()] - [ValidateSet('Public', 'Europe', 'Australia')] + [ValidateSet('Public', 'Europe', 'Australia', 'US')] [string] $Stamp = 'Public' ) begin { diff --git a/src/functions/public/Status/Get-GitHubStatusComponent.ps1 b/src/functions/public/Status/Get-GitHubStatusComponent.ps1 index 812d910c5..130c5af14 100644 --- a/src/functions/public/Status/Get-GitHubStatusComponent.ps1 +++ b/src/functions/public/Status/Get-GitHubStatusComponent.ps1 @@ -24,7 +24,7 @@ param( # The stamp to check status for. [Parameter()] - [ValidateSet('Public', 'Europe', 'Australia')] + [ValidateSet('Public', 'Europe', 'Australia', 'US')] [string] $Stamp = 'Public' ) diff --git a/src/functions/public/Status/Get-GitHubStatusIncident.ps1 b/src/functions/public/Status/Get-GitHubStatusIncident.ps1 index f591af37b..146c88f94 100644 --- a/src/functions/public/Status/Get-GitHubStatusIncident.ps1 +++ b/src/functions/public/Status/Get-GitHubStatusIncident.ps1 @@ -37,7 +37,7 @@ # The stamp to check status for. [Parameter()] - [ValidateSet('Public', 'Europe', 'Australia')] + [ValidateSet('Public', 'Europe', 'Australia', 'US')] [string] $Stamp = 'Public' ) diff --git a/src/variables/private/StatusBaseURL.ps1 b/src/variables/private/StatusBaseURL.ps1 index be2f94de8..a5ddbabdd 100644 --- a/src/variables/private/StatusBaseURL.ps1 +++ b/src/variables/private/StatusBaseURL.ps1 @@ -2,4 +2,5 @@ Public = 'https://www.githubstatus.com' Europe = 'https://eu.githubstatus.com' Australia = 'https://au.githubstatus.com' + US = 'https://us.githubstatus.com' } diff --git a/tests/GitHub.Tests.ps1 b/tests/GitHub.Tests.ps1 index dc23e96c1..2338eff02 100644 --- a/tests/GitHub.Tests.ps1 +++ b/tests/GitHub.Tests.ps1 @@ -226,7 +226,7 @@ Describe 'GitHub' { $runnerData | Should -Not -BeNullOrEmpty } } - Context 'Status' -ForEach @('Public', 'Europe', 'Australia') { + Context 'Status' -ForEach @('Public', 'Europe', 'Australia', 'US') { It 'Get-GitHubScheduledMaintenance - Gets scheduled maintenance for <_>' { { Get-GitHubScheduledMaintenance -Stamp $_ } | Should -Not -Throw } From 12288bd4ae4dc9dcde5ffbfbf3f09e8df4b72467 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Jul 2025 19:41:01 +0200 Subject: [PATCH 11/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Rename=20`$inpu?= =?UTF-8?q?tObject`=20variables=20to=20`$apiParams`=20in=20API=20calls=20(?= =?UTF-8?q?#464)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR improves code clarity by renaming misleading variable names in API parameter hashtables throughout the codebase. - Fixes #433 ## Problem Previously, the variable `$inputObject` was used to represent hashtables containing parameters for API requests. However, `$inputObject` typically implies pipeline input rather than API request parameters, making it confusing and misleading for developers maintaining the code. **Example of confusing usage:** ```powershell $inputObject = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Name" Context = $Context } Invoke-GitHubAPI @inputObject ``` ## Solution Renamed all occurrences of `$inputObject` used specifically for API request parameter hashtables to `$apiParams` for clarity and better readability. **After the change:** ```powershell $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Name" Context = $Context } Invoke-GitHubAPI @apiParams ``` ## Changes Made - **Files Modified:** 211 files total - **REST API calls:** 202 files with `Invoke-GitHubAPI @inputObject` → `Invoke-GitHubAPI @apiParams` - **GraphQL calls:** 9 files with `Invoke-GitHubGraphQLQuery @inputObject` → `Invoke-GitHubGraphQLQuery @apiParams` - **Lines Changed:** 595 insertions, 595 deletions (pure variable renaming) ## Scope ✅ **Changed**: All occurrences where `$inputObject` explicitly represents parameters passed to `Invoke-GitHubAPI` or `Invoke-GitHubGraphQLQuery` ✅ **Preserved**: Parameters named `$InputObject` intended for pipeline input objects (such as `[Parameter(ValueFromPipeline)]`) ## Validation - All PowerShell syntax validation passes - Pipeline parameters correctly preserved (e.g., `[GitHubVariable[]] $InputObject` in `Remove-GitHubVariable`) - Zero remaining `$inputObject` variables used with API calls - No functional changes - pure variable renaming ## Outcome Improved code clarity and maintainability, reducing potential confusion for future development and maintenance by clearly distinguishing API parameter hashtables from pipeline input parameters. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug --- examples/Organizations/Organization.ps1 | 2 +- examples/Repositories/Set-GitHubRepository.ps1 | 2 +- src/classes/public/App/GitHubApp.ps1 | 2 +- .../Actions/Workflow Run/Get-GitHubWorkflowRunByRepo.ps1 | 6 +++--- .../Workflow Run/Get-GitHubWorkflowRunByWorkflow.ps1 | 4 ++-- .../private/Apps/GitHub Apps/Get-GitHubAppBySlug.ps1 | 4 ++-- .../GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 | 4 ++-- .../Get-GitHubAppInstallationForAuthenticatedApp.ps1 | 4 ++-- .../private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 | 4 ++-- .../Get-GitHubEnterpriseOrganizationAppInstallation.ps1 | 4 ++-- .../GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 | 4 ++-- .../Install-GitHubAppOnEnterpriseOrganization.ps1 | 4 ++-- .../GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 | 4 ++-- .../GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 | 2 +- .../Uninstall-GitHubAppOnEnterpriseOrganization.ps1 | 4 ++-- src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 | 6 +++--- .../private/Artifacts/Get-GitHubArtifactFromRepository.ps1 | 6 +++--- .../private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 | 6 +++--- src/functions/private/Branches/Get-GitHubBranchList.ps1 | 4 ++-- .../private/Environments/Get-GitHubEnvironmentByName.ps1 | 6 +++--- .../private/Environments/Get-GitHubEnvironmentList.ps1 | 6 +++--- .../private/Gitignore/Get-GitHubGitignoreByName.ps1 | 4 ++-- src/functions/private/Gitignore/Get-GitHubGitignoreList.ps1 | 4 ++-- src/functions/private/License/Get-GitHubLicenseByName.ps1 | 4 ++-- src/functions/private/License/Get-GitHubLicenseList.ps1 | 4 ++-- .../private/License/Get-GitHubRepositoryLicense.ps1 | 4 ++-- .../Blocking/Block-GitHubUserByOrganization.ps1 | 4 ++-- .../Blocking/Get-GitHubBlockedUserByOrganization.ps1 | 4 ++-- .../Blocking/Test-GitHubBlockedUserByOrganization.ps1 | 4 ++-- .../Blocking/Unblock-GitHubUserByOrganization.ps1 | 4 ++-- .../private/Organization/Get-GitHubAllOrganization.ps1 | 4 ++-- .../private/Organization/Get-GitHubOrganizationByName.ps1 | 4 ++-- .../private/Organization/Get-GitHubUserOrganization.ps1 | 4 ++-- .../private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 | 4 ++-- .../Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 | 4 ++-- .../private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1 | 4 ++-- .../Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1 | 4 ++-- src/functions/private/Releases/Get-GitHubReleaseAll.ps1 | 4 ++-- src/functions/private/Releases/Get-GitHubReleaseByID.ps1 | 4 ++-- .../private/Releases/Get-GitHubReleaseByTagName.ps1 | 4 ++-- src/functions/private/Releases/Get-GitHubReleaseLatest.ps1 | 4 ++-- .../Autolinks/Get-GitHubRepositoryAutolinkById.ps1 | 4 ++-- .../Autolinks/Get-GitHubRepositoryAutolinkList.ps1 | 4 ++-- .../private/Repositories/Get-GitHubMyRepositories.ps1 | 4 ++-- .../private/Repositories/Get-GitHubMyRepositoryByName.ps1 | 4 ++-- .../private/Repositories/Get-GitHubRepositoryByName.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositoryByNameAndTeam.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositoryListByOwner.ps1 | 4 ++-- .../private/Repositories/Get-GitHubRepositoryListByTeam.ps1 | 4 ++-- .../private/Repositories/New-GitHubRepositoryAsFork.ps1 | 4 ++-- .../Repositories/New-GitHubRepositoryFromTemplate.ps1 | 4 ++-- .../private/Repositories/New-GitHubRepositoryOrg.ps1 | 4 ++-- .../private/Repositories/New-GitHubRepositoryUser.ps1 | 4 ++-- .../RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 | 4 ++-- .../RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 | 4 ++-- .../private/Secrets/Get-GitHubSecretEnvironmentByName.ps1 | 6 +++--- .../private/Secrets/Get-GitHubSecretEnvironmentList.ps1 | 6 +++--- .../private/Secrets/Get-GitHubSecretFromOrganization.ps1 | 6 +++--- .../private/Secrets/Get-GitHubSecretOwnerByName.ps1 | 6 +++--- src/functions/private/Secrets/Get-GitHubSecretOwnerList.ps1 | 6 +++--- .../private/Secrets/Get-GitHubSecretRepositoryByName.ps1 | 6 +++--- .../private/Secrets/Get-GitHubSecretRepositoryList.ps1 | 6 +++--- .../PublicKey/Get-GitHubPublicKeyForActionOnEnvironment.ps1 | 4 ++-- .../Get-GitHubPublicKeyForActionOnOrganization.ps1 | 4 ++-- .../PublicKey/Get-GitHubPublicKeyForActionOnRepository.ps1 | 4 ++-- .../Get-GitHubPublicKeyForCodespacesOnOrganization.ps1 | 4 ++-- .../Get-GitHubPublicKeyForCodespacesOnRepository.ps1 | 4 ++-- .../PublicKey/Get-GitHubPublicKeyForCodespacesOnUser.ps1 | 4 ++-- .../private/Secrets/Remove-GitHubSecretFromEnvironment.ps1 | 6 +++--- .../private/Secrets/Remove-GitHubSecretFromOwner.ps1 | 6 +++--- .../private/Secrets/Remove-GitHubSecretFromRepository.ps1 | 6 +++--- .../private/Secrets/Set-GitHubSecretOnEnvironment.ps1 | 6 +++--- src/functions/private/Secrets/Set-GitHubSecretOnOwner.ps1 | 6 +++--- .../private/Secrets/Set-GitHubSecretOnRepository.ps1 | 6 +++--- src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 | 4 ++-- src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 | 4 ++-- src/functions/private/Teams/Get-GitHubTeamListByRepo.ps1 | 4 ++-- .../private/Users/Blocking/Block-GitHubUserByUser.ps1 | 4 ++-- .../private/Users/Blocking/Get-GitHubBlockedUserByUser.ps1 | 4 ++-- .../private/Users/Blocking/Test-GitHubBlockedUserByUser.ps1 | 4 ++-- .../private/Users/Blocking/Unblock-GitHubUserByUser.ps1 | 4 ++-- .../private/Users/Emails/Get-GitHubUserAllEmail.ps1 | 4 ++-- .../private/Users/Emails/Get-GitHubUserPublicEmail.ps1 | 4 ++-- .../Users/Followers/Get-GitHubUserFollowersOfUser.ps1 | 4 ++-- .../private/Users/Followers/Get-GitHubUserFollowingMe.ps1 | 4 ++-- .../private/Users/Followers/Get-GitHubUserFollowingUser.ps1 | 4 ++-- .../private/Users/Followers/Get-GitHubUserMyFollower.ps1 | 4 ++-- .../private/Users/Followers/Test-GitHubUserFollowedByMe.ps1 | 4 ++-- .../Users/Followers/Test-GitHubUserFollowedByUser.ps1 | 4 ++-- .../private/Users/GPG-Keys/Get-GitHubUserGpgKeyForUser.ps1 | 4 ++-- .../private/Users/GPG-Keys/Get-GitHubUserMyGpgKey.ps1 | 4 ++-- .../private/Users/GPG-Keys/Get-GitHubUserMyGpgKeyById.ps1 | 4 ++-- src/functions/private/Users/Get-GitHubAllUser.ps1 | 4 ++-- src/functions/private/Users/Get-GitHubMyUser.ps1 | 4 ++-- src/functions/private/Users/Get-GitHubUserByName.ps1 | 4 ++-- .../private/Users/Keys/Get-GitHubUserKeyForUser.ps1 | 4 ++-- src/functions/private/Users/Keys/Get-GitHubUserMyKey.ps1 | 4 ++-- .../private/Users/Keys/Get-GitHubUserMyKeyById.ps1 | 4 ++-- .../Users/SSH-Signing-Keys/Get-GitHubUserMySigningKey.ps1 | 4 ++-- .../SSH-Signing-Keys/Get-GitHubUserMySigningKeyById.ps1 | 4 ++-- .../SSH-Signing-Keys/Get-GitHubUserSigningKeyForUser.ps1 | 4 ++-- .../Users/Social-Accounts/Get-GitHubMyUserSocials.ps1 | 4 ++-- .../Users/Social-Accounts/Get-GitHubUserSocialsByName.ps1 | 4 ++-- .../Variables/Get-GitHubVariableEnvironmentByName.ps1 | 6 +++--- .../private/Variables/Get-GitHubVariableEnvironmentList.ps1 | 6 +++--- .../Variables/Get-GitHubVariableFromOrganization.ps1 | 6 +++--- .../private/Variables/Get-GitHubVariableOwnerByName.ps1 | 6 +++--- .../private/Variables/Get-GitHubVariableOwnerList.ps1 | 6 +++--- .../Variables/Get-GitHubVariableRepositoryByName.ps1 | 6 +++--- .../private/Variables/Get-GitHubVariableRepositoryList.ps1 | 6 +++--- .../private/Variables/New-GitHubVariableOnEnvironment.ps1 | 6 +++--- .../private/Variables/New-GitHubVariableOnOwner.ps1 | 6 +++--- .../private/Variables/New-GitHubVariableOnRepository.ps1 | 6 +++--- .../Variables/Remove-GitHubVariableFromEnvironment.ps1 | 6 +++--- .../private/Variables/Remove-GitHubVariableFromOwner.ps1 | 6 +++--- .../Variables/Remove-GitHubVariableFromRepository.ps1 | 6 +++--- .../Variables/Update-GitHubVariableOnEnvironment.ps1 | 6 +++--- .../private/Variables/Update-GitHubVariableOnOwner.ps1 | 6 +++--- .../private/Variables/Update-GitHubVariableOnRepository.ps1 | 6 +++--- .../private/Webhooks/Get-GitHubAppWebhookDeliveryByID.ps1 | 4 ++-- .../private/Webhooks/Get-GitHubAppWebhookDeliveryByList.ps1 | 4 ++-- src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 | 4 ++-- .../Add-GitHubAppInstallationRepositoryAccess.ps1 | 4 ++-- .../Get-GitHubAppAccessibleRepository.ps1 | 4 ++-- .../Get-GitHubAppInstallationRepositoryAccess.ps1 | 4 ++-- .../Remove-GitHubAppInstallationRepositoryAccess.ps1 | 4 ++-- .../Update-GitHubAppInstallationRepositoryAccess.ps1 | 4 ++-- .../Apps/GitHub App/Get-GitHubAppInstallationRequest.ps1 | 4 ++-- src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 | 4 ++-- src/functions/public/Artifacts/Save-GitHubArtifact.ps1 | 4 ++-- src/functions/public/Emojis/Get-GitHubEmoji.ps1 | 4 ++-- .../public/Environments/Remove-GitHubEnvironment.ps1 | 4 ++-- src/functions/public/Environments/Set-GitHubEnvironment.ps1 | 4 ++-- src/functions/public/Markdown/Get-GitHubMarkdown.ps1 | 4 ++-- src/functions/public/Markdown/Get-GitHubMarkdownRaw.ps1 | 4 ++-- src/functions/public/Meta/Get-GitHubApiVersion.ps1 | 4 ++-- src/functions/public/Meta/Get-GitHubMeta.ps1 | 4 ++-- src/functions/public/Meta/Get-GitHubOctocat.ps1 | 4 ++-- src/functions/public/Meta/Get-GitHubRoot.ps1 | 4 ++-- src/functions/public/Meta/Get-GitHubZen.ps1 | 4 ++-- .../Organization/Members/Get-GitHubOrganizationMember.ps1 | 4 ++-- .../Members/Get-GitHubOrganizationPendingInvitation.ps1 | 4 ++-- .../Members/New-GitHubOrganizationInvitation.ps1 | 4 ++-- .../Members/Remove-GitHubOrganizationInvitation.ps1 | 4 ++-- .../public/Organization/Update-GitHubOrganization.ps1 | 4 ++-- src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 | 4 ++-- .../public/Releases/Assets/Add-GitHubReleaseAsset.ps1 | 4 ++-- .../public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 | 4 ++-- .../public/Releases/Assets/Save-GitHubReleaseAsset.ps1 | 4 ++-- .../public/Releases/Assets/Update-GitHubReleaseAsset.ps1 | 4 ++-- src/functions/public/Releases/New-GitHubRelease.ps1 | 4 ++-- src/functions/public/Releases/New-GitHubReleaseNote.ps1 | 4 ++-- src/functions/public/Releases/Remove-GitHubRelease.ps1 | 4 ++-- src/functions/public/Releases/Update-GitHubRelease.ps1 | 4 ++-- .../Repositories/Autolinks/New-GitHubRepositoryAutolink.ps1 | 4 ++-- .../Autolinks/Remove-GitHubRepositoryAutolink.ps1 | 4 ++-- .../CustomProperties/Get-GitHubRepositoryCustomProperty.ps1 | 4 ++-- src/functions/public/Repositories/Move-GitHubRepository.ps1 | 4 ++-- .../Permissions/Remove-GitHubRepositoryPermission.ps1 | 4 ++-- .../Permissions/Set-GitHubRepositoryPermission.ps1 | 4 ++-- .../public/Repositories/Remove-GitHubRepository.ps1 | 4 ++-- ...isable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 | 4 ++-- .../Repositories/Disable-GitHubRepositorySecurityFix.ps1 | 4 ++-- .../Disable-GitHubRepositoryVulnerabilityAlert.ps1 | 4 ++-- ...Enable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 | 4 ++-- .../Repositories/Enable-GitHubRepositorySecurityFix.ps1 | 4 ++-- .../Enable-GitHubRepositoryVulnerabilityAlert.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositoryActivity.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositoryCodeownersError.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositoryContributor.ps1 | 4 ++-- .../Repositories/Repositories/Get-GitHubRepositoryFork.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositoryLanguage.ps1 | 4 ++-- .../Repositories/Get-GitHubRepositorySecurityFix.ps1 | 4 ++-- .../Repositories/Repositories/Get-GitHubRepositoryTag.ps1 | 4 ++-- .../Repositories/Repositories/Get-GitHubRepositoryTeam.ps1 | 4 ++-- .../Repositories/Repositories/Get-GitHubRepositoryTopic.ps1 | 4 ++-- .../Repositories/Repositories/Set-GitHubRepositoryTopic.ps1 | 4 ++-- .../Repositories/Start-GitHubRepositoryEvent.ps1 | 4 ++-- .../Test-GitHubRepositoryVulnerabilityAlert.ps1 | 4 ++-- .../public/Repositories/Update-GitHubRepository.ps1 | 4 ++-- .../Add-GitHubSecretSelectedRepository.ps1 | 4 ++-- .../Get-GitHubSecretSelectedRepository.ps1 | 4 ++-- .../Remove-GitHubSecretSelectedRepository.ps1 | 4 ++-- .../Set-GitHubSecretSelectedRepository.ps1 | 4 ++-- src/functions/public/Teams/New-GitHubTeam.ps1 | 4 ++-- src/functions/public/Teams/Remove-GitHubTeam.ps1 | 4 ++-- src/functions/public/Teams/Update-GitHubTeam.ps1 | 4 ++-- src/functions/public/Users/Emails/Add-GitHubUserEmail.ps1 | 4 ++-- .../public/Users/Emails/Remove-GitHubUserEmail.ps1 | 4 ++-- .../Users/Emails/Update-GitHubUserEmailVisibility.ps1 | 4 ++-- .../public/Users/Followers/Add-GitHubUserFollowing.ps1 | 4 ++-- .../public/Users/Followers/Remove-GitHubUserFollowing.ps1 | 4 ++-- .../public/Users/GPG-Keys/Add-GitHubUserGpgKey.ps1 | 4 ++-- .../public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 | 4 ++-- src/functions/public/Users/Keys/Add-GitHubUserKey.ps1 | 4 ++-- src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 | 4 ++-- .../Users/SSH-Signing-Keys/Add-GitHubUserSigningKey.ps1 | 4 ++-- .../Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 | 4 ++-- .../public/Users/Social-Accounts/Add-GitHubUserSocial.ps1 | 4 ++-- .../Users/Social-Accounts/Remove-GitHubUserSocial.ps1 | 4 ++-- src/functions/public/Users/Update-GitHubUser.ps1 | 4 ++-- .../Add-GitHubVariableSelectedRepository.ps1 | 4 ++-- .../Get-GitHubVariableSelectedRepository.ps1 | 4 ++-- .../Remove-GitHubVariableSelectedRepository.ps1 | 4 ++-- .../Set-GitHubVariableSelectedRepository.ps1 | 4 ++-- .../public/Webhooks/Get-GitHubAppWebhookConfiguration.ps1 | 4 ++-- .../public/Webhooks/Invoke-GitHubAppWebhookReDelivery.ps1 | 4 ++-- .../Webhooks/Update-GitHubAppWebhookConfiguration.ps1 | 4 ++-- src/functions/public/Workflows/Disable-GitHubWorkflow.ps1 | 4 ++-- src/functions/public/Workflows/Enable-GitHubWorkflow.ps1 | 4 ++-- src/functions/public/Workflows/Get-GitHubWorkflow.ps1 | 4 ++-- .../public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 | 4 ++-- .../public/Workflows/Runs/Restart-GitHubWorkflowRun.ps1 | 4 ++-- .../public/Workflows/Runs/Stop-GitHubWorkflowRun.ps1 | 4 ++-- src/functions/public/Workflows/Start-GitHubWorkflow.ps1 | 4 ++-- 215 files changed, 461 insertions(+), 461 deletions(-) diff --git a/examples/Organizations/Organization.ps1 b/examples/Organizations/Organization.ps1 index 4e4fcfbe3..9804a45f2 100644 --- a/examples/Organizations/Organization.ps1 +++ b/examples/Organizations/Organization.ps1 @@ -1,4 +1,4 @@ -$orgParam = @{ +$orgParam = @{ Enterprise = 'msx' Name = 'Marius-Test7' Owner = 'GitHub-Automation' diff --git a/examples/Repositories/Set-GitHubRepository.ps1 b/examples/Repositories/Set-GitHubRepository.ps1 index 2d82d9529..4e4d99def 100644 --- a/examples/Repositories/Set-GitHubRepository.ps1 +++ b/examples/Repositories/Set-GitHubRepository.ps1 @@ -1,4 +1,4 @@ -$params = @{ +$params = @{ Owner = 'octocat' Name = 'Hello-World' AllowSquashMergingWith = 'Pull request title and description' diff --git a/src/classes/public/App/GitHubApp.ps1 b/src/classes/public/App/GitHubApp.ps1 index 45dd6fff5..620f52af5 100644 --- a/src/classes/public/App/GitHubApp.ps1 +++ b/src/classes/public/App/GitHubApp.ps1 @@ -1,4 +1,4 @@ -class GitHubApp : GitHubNode { +class GitHubApp : GitHubNode { # The unique ID of the app [System.Nullable[UInt64]] $ID diff --git a/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByRepo.ps1 b/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByRepo.ps1 index f6f8dd9b1..9f756123c 100644 --- a/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByRepo.ps1 +++ b/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByRepo.ps1 @@ -1,4 +1,4 @@ -filter Get-GitHubWorkflowRunByRepo { +filter Get-GitHubWorkflowRunByRepo { <# .SYNOPSIS List workflow runs for a repository. @@ -108,7 +108,7 @@ filter Get-GitHubWorkflowRunByRepo { } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/runs" Body = $body @@ -116,7 +116,7 @@ filter Get-GitHubWorkflowRunByRepo { Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.workflow_runs | ForEach-Object { [GitHubWorkflowRun]::new($_) } diff --git a/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByWorkflow.ps1 b/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByWorkflow.ps1 index 9b362463c..918fd069d 100644 --- a/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByWorkflow.ps1 +++ b/src/functions/private/Actions/Workflow Run/Get-GitHubWorkflowRunByWorkflow.ps1 @@ -113,7 +113,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Context = $Context APIEndpoint = "/repos/$Owner/$Repository/actions/workflows/$ID/runs" Method = 'GET' @@ -121,7 +121,7 @@ Body = $body } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.workflow_runs | ForEach-Object { [GitHubWorkflowRun]::new($_) } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppBySlug.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppBySlug.ps1 index 7709015e3..ce921c706 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppBySlug.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppBySlug.ps1 @@ -35,13 +35,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/apps/$Slug" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubApp]::new($_.Response) } } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 index 5c03bfcfb..06e229ebd 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/enterprises/$Enterprise/apps/installable_organizations" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($organization in $_.Response) { [GitHubOrganization]::new($organization, $Context) } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 index a4a218574..afbe9e03c 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 @@ -39,14 +39,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/app/installations' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($installation in $_.Response) { [GitHubAppInstallation]::new($installation) } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 index bfa58d061..9686c3cfa 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 @@ -35,13 +35,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/app' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubApp]::new($_.Response) } } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 index ea19a3c4d..014e1bcfa 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 @@ -53,14 +53,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($installation in $_.Response) { [GitHubAppInstallation]::new($installation, $Organization, 'Organization', $Context) } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 index 5df95b3fd..dafc037a7 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 @@ -45,14 +45,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/installations" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($installation in $_.Response.installations) { [GitHubAppInstallation]::new($installation) } diff --git a/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 index d8d847476..d417c0628 100644 --- a/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1 @@ -60,14 +60,14 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations" Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubAppInstallation]::new($_.Response) } } diff --git a/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 index 34369ff47..142f8370a 100644 --- a/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 +++ b/src/functions/private/Apps/GitHub Apps/New-GitHubAppInstallationAccessToken.ps1 @@ -73,13 +73,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/app/installations/$ID/access_tokens" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [pscustomobject]@{ Token = $_.Response.token | ConvertTo-SecureString -AsPlainText -Force ExpiresAt = $_.Response.expires_at.ToLocalTime() diff --git a/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 b/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 index a5f6864d6..d6f845b8b 100644 --- a/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Revoke-GitHubAppInstallationAccessToken.ps1 @@ -1,4 +1,4 @@ -function Revoke-GitHubAppInstallationAccessToken { +function Revoke-GitHubAppInstallationAccessToken { <# .SYNOPSIS Revoke an installation access token. diff --git a/src/functions/private/Apps/GitHub Apps/Uninstall-GitHubAppOnEnterpriseOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Uninstall-GitHubAppOnEnterpriseOrganization.ps1 index 2cbf0b22a..cfea6ff04 100644 --- a/src/functions/private/Apps/GitHub Apps/Uninstall-GitHubAppOnEnterpriseOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Uninstall-GitHubAppOnEnterpriseOrganization.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 b/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 index 782667043..0c0c911b0 100644 --- a/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 +++ b/src/functions/private/Artifacts/Get-GitHubArtifactById.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubArtifactById { +function Get-GitHubArtifactById { <# .SYNOPSIS Retrieves a specific artifact from a GitHub Actions workflow run. @@ -61,13 +61,13 @@ function Get-GitHubArtifactById { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/artifacts/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubArtifact]::new($_.Response, $Owner, $Repository, $Context) } } diff --git a/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 b/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 index 08087d229..8b12374ce 100644 --- a/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 +++ b/src/functions/private/Artifacts/Get-GitHubArtifactFromRepository.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubArtifactFromRepository { +function Get-GitHubArtifactFromRepository { <# .SYNOPSIS Lists artifacts for a GitHub repository. @@ -69,14 +69,14 @@ function Get-GitHubArtifactFromRepository { } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/artifacts" Body = $body Context = $Context } - $response = Invoke-GitHubAPI @inputObject + $response = Invoke-GitHubAPI @apiParams $artifacts = $response.Response.artifacts | Sort-Object -Property created_at -Descending diff --git a/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 b/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 index 7a54c1709..07b2c9522 100644 --- a/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 +++ b/src/functions/private/Artifacts/Get-GitHubArtifactFromWorkflowRun.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubArtifactFromWorkflowRun { +function Get-GitHubArtifactFromWorkflowRun { <# .SYNOPSIS Retrieves artifacts from a specific GitHub Actions workflow run. @@ -80,14 +80,14 @@ function Get-GitHubArtifactFromWorkflowRun { } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/runs/$ID/artifacts" Body = $body Context = $Context } - $response = Invoke-GitHubAPI @inputObject + $response = Invoke-GitHubAPI @apiParams $artifacts = $response.Response.artifacts | Sort-Object -Property created_at -Descending diff --git a/src/functions/private/Branches/Get-GitHubBranchList.ps1 b/src/functions/private/Branches/Get-GitHubBranchList.ps1 index a036ccae7..f68175b86 100644 --- a/src/functions/private/Branches/Get-GitHubBranchList.ps1 +++ b/src/functions/private/Branches/Get-GitHubBranchList.ps1 @@ -37,13 +37,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/branches" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 b/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 index 0b9df7f01..bd0c7392d 100644 --- a/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 +++ b/src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1 @@ -1,4 +1,4 @@ -filter Get-GitHubEnvironmentByName { +filter Get-GitHubEnvironmentByName { <# .SYNOPSIS Retrieves details of a specified GitHub environment. @@ -80,13 +80,13 @@ filter Get-GitHubEnvironmentByName { process { $encodedName = [System.Uri]::EscapeDataString($Name) - $inputObject = @{ + $apiParams = @{ Method = 'GET' Uri = $Context.ApiBaseUri + "/repos/$Owner/$Repository/environments/$encodedName" Context = $Context } try { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubEnvironment]::new($_.Response, $Owner, $Repository, $Context) } } catch { diff --git a/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 b/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 index c4cd691bb..3748f44a8 100644 --- a/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 +++ b/src/functions/private/Environments/Get-GitHubEnvironmentList.ps1 @@ -1,4 +1,4 @@ -filter Get-GitHubEnvironmentList { +filter Get-GitHubEnvironmentList { <# .SYNOPSIS Lists the environments for a repository. @@ -74,14 +74,14 @@ filter Get-GitHubEnvironmentList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/environments" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($environment in $_.Response.environments) { [GitHubEnvironment]::new($environment, $Owner, $Repository, $Context) } diff --git a/src/functions/private/Gitignore/Get-GitHubGitignoreByName.ps1 b/src/functions/private/Gitignore/Get-GitHubGitignoreByName.ps1 index 89688cc4d..c79cc95f5 100644 --- a/src/functions/private/Gitignore/Get-GitHubGitignoreByName.ps1 +++ b/src/functions/private/Gitignore/Get-GitHubGitignoreByName.ps1 @@ -34,14 +34,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/gitignore/templates/$Name" Accept = 'application/vnd.github.raw+json' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Gitignore/Get-GitHubGitignoreList.ps1 b/src/functions/private/Gitignore/Get-GitHubGitignoreList.ps1 index 1e12c0e8d..fc6f70114 100644 --- a/src/functions/private/Gitignore/Get-GitHubGitignoreList.ps1 +++ b/src/functions/private/Gitignore/Get-GitHubGitignoreList.ps1 @@ -32,13 +32,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/gitignore/templates' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/License/Get-GitHubLicenseByName.ps1 b/src/functions/private/License/Get-GitHubLicenseByName.ps1 index 42a0da42b..e1924aaff 100644 --- a/src/functions/private/License/Get-GitHubLicenseByName.ps1 +++ b/src/functions/private/License/Get-GitHubLicenseByName.ps1 @@ -36,14 +36,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/licenses/$Name" Accept = 'application/vnd.github+json' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubLicense]::New($_.Response) } } diff --git a/src/functions/private/License/Get-GitHubLicenseList.ps1 b/src/functions/private/License/Get-GitHubLicenseList.ps1 index 03bcf4add..436596194 100644 --- a/src/functions/private/License/Get-GitHubLicenseList.ps1 +++ b/src/functions/private/License/Get-GitHubLicenseList.ps1 @@ -35,13 +35,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/licenses' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response | ForEach-Object { [GitHubLicense]::New($_) } } } diff --git a/src/functions/private/License/Get-GitHubRepositoryLicense.ps1 b/src/functions/private/License/Get-GitHubRepositoryLicense.ps1 index c6fdefe6a..31e4dfd1e 100644 --- a/src/functions/private/License/Get-GitHubRepositoryLicense.ps1 +++ b/src/functions/private/License/Get-GitHubRepositoryLicense.ps1 @@ -54,14 +54,14 @@ 'html' { 'application/vnd.github.html+json' } } - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/license" ContentType = $contentType Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $Response = $_.Response $rawContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Response.content)) $Response | Add-Member -NotePropertyName 'raw_content' -NotePropertyValue $rawContent -Force diff --git a/src/functions/private/Organization/Blocking/Block-GitHubUserByOrganization.ps1 b/src/functions/private/Organization/Blocking/Block-GitHubUserByOrganization.ps1 index 90b9e5602..d25d9f1e2 100644 --- a/src/functions/private/Organization/Blocking/Block-GitHubUserByOrganization.ps1 +++ b/src/functions/private/Organization/Blocking/Block-GitHubUserByOrganization.ps1 @@ -49,13 +49,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$Organization/blocks/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Organization/Blocking/Get-GitHubBlockedUserByOrganization.ps1 b/src/functions/private/Organization/Blocking/Get-GitHubBlockedUserByOrganization.ps1 index 38f98d8f9..5830f3a51 100644 --- a/src/functions/private/Organization/Blocking/Get-GitHubBlockedUserByOrganization.ps1 +++ b/src/functions/private/Organization/Blocking/Get-GitHubBlockedUserByOrganization.ps1 @@ -39,14 +39,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/blocks" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Organization/Blocking/Test-GitHubBlockedUserByOrganization.ps1 b/src/functions/private/Organization/Blocking/Test-GitHubBlockedUserByOrganization.ps1 index 5a6a1729e..b2dbc1fac 100644 --- a/src/functions/private/Organization/Blocking/Test-GitHubBlockedUserByOrganization.ps1 +++ b/src/functions/private/Organization/Blocking/Test-GitHubBlockedUserByOrganization.ps1 @@ -48,13 +48,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/blocks/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Organization/Blocking/Unblock-GitHubUserByOrganization.ps1 b/src/functions/private/Organization/Blocking/Unblock-GitHubUserByOrganization.ps1 index feac1635c..384cf5a73 100644 --- a/src/functions/private/Organization/Blocking/Unblock-GitHubUserByOrganization.ps1 +++ b/src/functions/private/Organization/Blocking/Unblock-GitHubUserByOrganization.ps1 @@ -49,12 +49,12 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Organization/blocks/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 b/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 index 60f8aee2f..159d39b7f 100644 --- a/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubAllOrganization.ps1 @@ -49,7 +49,7 @@ since = $Since } - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/organizations' Body = $body @@ -57,7 +57,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($organization in $_.Response) { [GitHubOrganization]::new($organization, $Context) } diff --git a/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 b/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 index aee398ab2..87b512ae2 100644 --- a/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 +++ b/src/functions/private/Organization/Get-GitHubOrganizationByName.ps1 @@ -49,13 +49,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubOrganization]::new($_.Response, $Context) } } diff --git a/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 b/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 index 6cd3d6e9b..f76da4920 100644 --- a/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 +++ b/src/functions/private/Organization/Get-GitHubUserOrganization.ps1 @@ -47,14 +47,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/orgs" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($organization in $_.Response) { [GitHubOrganization]::new($organization, $Context) } diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 index d2a53b506..dc7e238b9 100644 --- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 +++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 @@ -48,13 +48,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/releases/assets/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubReleaseAsset]($_.Response) } } diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 index 54db2d1a6..c8215d842 100644 --- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 +++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 @@ -55,14 +55,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/releases/$ID/assets" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($asset in $_.Response) { if ($PSBoundParameters.ContainsKey('Name')) { if ($asset.name -eq $Name) { diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1 index 2dfabdc9f..ad523dcc0 100644 --- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1 +++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1 @@ -70,7 +70,7 @@ $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context do { - $inputObject = @{ + $apiParams = @{ Query = @" query(`$owner: String!, `$repository: String!, `$tag: String!, `$perPage: Int, `$after: String) { repository(owner: `$owner, name: `$repository) { @@ -109,7 +109,7 @@ query(`$owner: String!, `$repository: String!, `$tag: String!, `$perPage: Int, ` Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { $release = $_.repository.release $assets = $release.releaseAssets foreach ($asset in $assets.nodes) { diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1 index 2d7c7efd3..c0bbde666 100644 --- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1 +++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1 @@ -70,7 +70,7 @@ $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context do { - $inputObject = @{ + $apiParams = @{ Query = @" query(`$owner: String!, `$repository: String!, `$perPage: Int, `$after: String) { repository(owner: `$owner, name: `$repository) { @@ -108,7 +108,7 @@ query(`$owner: String!, `$repository: String!, `$perPage: Int, `$after: String) Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { $release = $_.repository.latestRelease $assets = $release.releaseAssets foreach ($asset in $assets.nodes) { diff --git a/src/functions/private/Releases/Get-GitHubReleaseAll.ps1 b/src/functions/private/Releases/Get-GitHubReleaseAll.ps1 index 5603893cc..4e04235f7 100644 --- a/src/functions/private/Releases/Get-GitHubReleaseAll.ps1 +++ b/src/functions/private/Releases/Get-GitHubReleaseAll.ps1 @@ -63,7 +63,7 @@ $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context do { - $inputObject = @{ + $apiParams = @{ Query = @' query($owner: String!, $repository: String!, $perPage: Int, $after: String) { repository(owner: $owner, name: $repository) { @@ -102,7 +102,7 @@ query($owner: String!, $repository: String!, $perPage: Int, $after: String) { Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { foreach ($release in $_.repository.releases.nodes) { [GitHubRelease]::new($release, $Owner, $Repository, $null) } diff --git a/src/functions/private/Releases/Get-GitHubReleaseByID.ps1 b/src/functions/private/Releases/Get-GitHubReleaseByID.ps1 index 126d87e8e..0fa9cf1f7 100644 --- a/src/functions/private/Releases/Get-GitHubReleaseByID.ps1 +++ b/src/functions/private/Releases/Get-GitHubReleaseByID.ps1 @@ -51,14 +51,14 @@ process { $latest = Get-GitHubReleaseLatest -Owner $Owner -Repository $Repository -Context $Context - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/releases/$ID" Context = $Context } try { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $isLatest = $_.Response.id -eq $latest.id [GitHubRelease]::new($_.Response, $Owner, $Repository, $isLatest) } diff --git a/src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1 b/src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1 index d3e29e765..7577e5c7e 100644 --- a/src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1 +++ b/src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1 @@ -48,7 +48,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Query = @' query($owner: String!, $repository: String!, $tag: String!) { repository(owner: $owner, name: $repository) { @@ -80,7 +80,7 @@ query($owner: String!, $repository: String!, $tag: String!) { Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { $release = $_.repository.release if ($release) { [GitHubRelease]::new($release, $Owner, $Repository, $null) diff --git a/src/functions/private/Releases/Get-GitHubReleaseLatest.ps1 b/src/functions/private/Releases/Get-GitHubReleaseLatest.ps1 index a0bddf908..221afdbb1 100644 --- a/src/functions/private/Releases/Get-GitHubReleaseLatest.ps1 +++ b/src/functions/private/Releases/Get-GitHubReleaseLatest.ps1 @@ -46,7 +46,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Query = @' query($owner: String!, $repository: String!) { repository(owner: $owner, name: $repository) { @@ -77,7 +77,7 @@ query($owner: String!, $repository: String!) { Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { $release = $_.repository.latestRelease if ($release) { [GitHubRelease]::new($release, $Owner, $Repository, $null) diff --git a/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkById.ps1 b/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkById.ps1 index 911d64a31..64dad648a 100644 --- a/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkById.ps1 +++ b/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkById.ps1 @@ -48,13 +48,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/autolinks/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkList.ps1 b/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkList.ps1 index 909c59277..cda80c94d 100644 --- a/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkList.ps1 +++ b/src/functions/private/Repositories/Autolinks/Get-GitHubRepositoryAutolinkList.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/autolinks" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Repositories/Get-GitHubMyRepositories.ps1 b/src/functions/private/Repositories/Get-GitHubMyRepositories.ps1 index 1129e56b5..f79bdc32e 100644 --- a/src/functions/private/Repositories/Get-GitHubMyRepositories.ps1 +++ b/src/functions/private/Repositories/Get-GitHubMyRepositories.ps1 @@ -85,7 +85,7 @@ $graphQLFields = ConvertTo-GitHubGraphQLField @graphParams do { - $inputObject = @{ + $apiParams = @{ Query = @" query( `$PerPage: Int!, @@ -126,7 +126,7 @@ $graphQLFields Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { $_.viewer.repositories.nodes | ForEach-Object { [GitHubRepository]::new($_) } diff --git a/src/functions/private/Repositories/Get-GitHubMyRepositoryByName.ps1 b/src/functions/private/Repositories/Get-GitHubMyRepositoryByName.ps1 index c43967ee5..14d125396 100644 --- a/src/functions/private/Repositories/Get-GitHubMyRepositoryByName.ps1 +++ b/src/functions/private/Repositories/Get-GitHubMyRepositoryByName.ps1 @@ -105,7 +105,7 @@ } $graphQLFields = ConvertTo-GitHubGraphQLField @graphParams - $inputObject = @{ + $apiParams = @{ Query = @" query( `$Name: String! @@ -125,7 +125,7 @@ $graphQLFields Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { [GitHubRepository]::new($_.viewer.repository) } } diff --git a/src/functions/private/Repositories/Get-GitHubRepositoryByName.ps1 b/src/functions/private/Repositories/Get-GitHubRepositoryByName.ps1 index 3238fbe35..06d6cd896 100644 --- a/src/functions/private/Repositories/Get-GitHubRepositoryByName.ps1 +++ b/src/functions/private/Repositories/Get-GitHubRepositoryByName.ps1 @@ -108,7 +108,7 @@ } $graphQLFields = ConvertTo-GitHubGraphQLField @graphParams - $inputObject = @{ + $apiParams = @{ Query = @" query( `$Owner: String!, @@ -132,7 +132,7 @@ $graphQLFields Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { [GitHubRepository]::new($_.repositoryOwner.repository) } } diff --git a/src/functions/private/Repositories/Get-GitHubRepositoryByNameAndTeam.ps1 b/src/functions/private/Repositories/Get-GitHubRepositoryByNameAndTeam.ps1 index f430e3e9b..594ed1ed8 100644 --- a/src/functions/private/Repositories/Get-GitHubRepositoryByNameAndTeam.ps1 +++ b/src/functions/private/Repositories/Get-GitHubRepositoryByNameAndTeam.ps1 @@ -60,14 +60,14 @@ process { $TeamOwner = [string]::IsNullOrEmpty($TeamOwner) ? $Owner : $TeamOwner - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$TeamOwner/teams/$Team/repos/$Owner/$Name" Accept = 'application/vnd.github.v3.repository+json' Context = $Context } try { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRepository]::new($_.Response) } } catch { diff --git a/src/functions/private/Repositories/Get-GitHubRepositoryListByOwner.ps1 b/src/functions/private/Repositories/Get-GitHubRepositoryListByOwner.ps1 index d2c20bb19..6476885ec 100644 --- a/src/functions/private/Repositories/Get-GitHubRepositoryListByOwner.ps1 +++ b/src/functions/private/Repositories/Get-GitHubRepositoryListByOwner.ps1 @@ -93,7 +93,7 @@ $graphQLFields = ConvertTo-GitHubGraphQLField @graphParams do { - $inputObject = @{ + $apiParams = @{ Query = @" query( `$Owner: String!, @@ -141,7 +141,7 @@ query( Context = $Context } - Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object { + Invoke-GitHubGraphQLQuery @apiParams | ForEach-Object { foreach ($repository in $_.repositoryOwner.repositories.nodes) { [GitHubRepository]::new($repository) } diff --git a/src/functions/private/Repositories/Get-GitHubRepositoryListByTeam.ps1 b/src/functions/private/Repositories/Get-GitHubRepositoryListByTeam.ps1 index 3c2628de8..95e2c9238 100644 --- a/src/functions/private/Repositories/Get-GitHubRepositoryListByTeam.ps1 +++ b/src/functions/private/Repositories/Get-GitHubRepositoryListByTeam.ps1 @@ -50,13 +50,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/teams/$Team/repos" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($repo in $_.Response) { [GitHubRepository]::new($repo) } diff --git a/src/functions/private/Repositories/New-GitHubRepositoryAsFork.ps1 b/src/functions/private/Repositories/New-GitHubRepositoryAsFork.ps1 index 6ec895950..b29c11f2a 100644 --- a/src/functions/private/Repositories/New-GitHubRepositoryAsFork.ps1 +++ b/src/functions/private/Repositories/New-GitHubRepositoryAsFork.ps1 @@ -83,7 +83,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$ForkOwner/$ForkRepository/forks" Body = $body @@ -91,7 +91,7 @@ } if ($PSCmdlet.ShouldProcess("Repository [$Owner/$Name] as fork of [$ForkOwner/$ForkRepository]", 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRepository]::New($_.Response) } } diff --git a/src/functions/private/Repositories/New-GitHubRepositoryFromTemplate.ps1 b/src/functions/private/Repositories/New-GitHubRepositoryFromTemplate.ps1 index 6a1054b4a..388483be0 100644 --- a/src/functions/private/Repositories/New-GitHubRepositoryFromTemplate.ps1 +++ b/src/functions/private/Repositories/New-GitHubRepositoryFromTemplate.ps1 @@ -92,7 +92,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$TemplateOwner/$TemplateRepository/generate" Body = $body @@ -100,7 +100,7 @@ } if ($PSCmdlet.ShouldProcess("Repository [$Owner/$Name] from template [$TemplateOwner/$TemplateRepository]", 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRepository]::New($_.Response) } } diff --git a/src/functions/private/Repositories/New-GitHubRepositoryOrg.ps1 b/src/functions/private/Repositories/New-GitHubRepositoryOrg.ps1 index 6f827aa41..8a4b91906 100644 --- a/src/functions/private/Repositories/New-GitHubRepositoryOrg.ps1 +++ b/src/functions/private/Repositories/New-GitHubRepositoryOrg.ps1 @@ -182,7 +182,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/orgs/$Organization/repos" Body = $body @@ -190,7 +190,7 @@ } if ($PSCmdlet.ShouldProcess("Repository [$Name] in organization [$Organization]", 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRepository]::New($_.Response) } } diff --git a/src/functions/private/Repositories/New-GitHubRepositoryUser.ps1 b/src/functions/private/Repositories/New-GitHubRepositoryUser.ps1 index 873b72abe..fbfaf3406 100644 --- a/src/functions/private/Repositories/New-GitHubRepositoryUser.ps1 +++ b/src/functions/private/Repositories/New-GitHubRepositoryUser.ps1 @@ -180,7 +180,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/user/repos' Body = $body @@ -188,7 +188,7 @@ } if ($PSCmdlet.ShouldProcess('Repository for user', 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRepository]::New($_.Response) } } diff --git a/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 index e614f7f10..9e80908b9 100644 --- a/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 +++ b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteById.ps1 @@ -48,13 +48,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/rulesets/rule-suites/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 index 7843a405b..629992264 100644 --- a/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 +++ b/src/functions/private/Repositories/RuleSuite/Get-GitHubRepositoryRuleSuiteList.ps1 @@ -85,7 +85,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/rulesets/rule-suites" Body = $body @@ -93,7 +93,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Secrets/Get-GitHubSecretEnvironmentByName.ps1 b/src/functions/private/Secrets/Get-GitHubSecretEnvironmentByName.ps1 index 221c84b02..669765d48 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretEnvironmentByName.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretEnvironmentByName.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretEnvironmentByName { +function Get-GitHubSecretEnvironmentByName { <# .SYNOPSIS Get an environment secret. @@ -62,13 +62,13 @@ function Get-GitHubSecretEnvironmentByName { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/secrets/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubSecret]::new($_.Response, $Owner, $Repository, $Environment, $null) } } diff --git a/src/functions/private/Secrets/Get-GitHubSecretEnvironmentList.ps1 b/src/functions/private/Secrets/Get-GitHubSecretEnvironmentList.ps1 index 355a2ae73..6f63d6c15 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretEnvironmentList.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretEnvironmentList.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretEnvironmentList { +function Get-GitHubSecretEnvironmentList { <# .SYNOPSIS List environment secrets. @@ -64,13 +64,13 @@ function Get-GitHubSecretEnvironmentList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/secrets" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.secrets | ForEach-Object { [GitHubSecret]::new($_, $Owner, $Repository, $Environment, $null) } diff --git a/src/functions/private/Secrets/Get-GitHubSecretFromOrganization.ps1 b/src/functions/private/Secrets/Get-GitHubSecretFromOrganization.ps1 index 1fa1784c9..67df30aa0 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretFromOrganization.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretFromOrganization.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretFromOrganization { +function Get-GitHubSecretFromOrganization { <# .SYNOPSIS List repository organization secrets. @@ -81,7 +81,7 @@ function Get-GitHubSecretFromOrganization { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/organization-secrets" PerPage = $PerPage @@ -89,7 +89,7 @@ function Get-GitHubSecretFromOrganization { } try { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.secrets | ForEach-Object { [GitHubSecret]::new($_, $Owner, $null, $null, $null) } diff --git a/src/functions/private/Secrets/Get-GitHubSecretOwnerByName.ps1 b/src/functions/private/Secrets/Get-GitHubSecretOwnerByName.ps1 index d5b44d7e7..97179d7fe 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretOwnerByName.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretOwnerByName.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretOwnerByName { +function Get-GitHubSecretOwnerByName { <# .SYNOPSIS Create or update an organization secret. @@ -55,13 +55,13 @@ function Get-GitHubSecretOwnerByName { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $selectedRepositories = @() if ($_.Response.visibility -eq 'selected') { $selectedRepositories = Get-GitHubSecretSelectedRepository -Owner $Owner -Name $_.Response.name -Context $Context diff --git a/src/functions/private/Secrets/Get-GitHubSecretOwnerList.ps1 b/src/functions/private/Secrets/Get-GitHubSecretOwnerList.ps1 index 81faca4af..0289fb8ea 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretOwnerList.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretOwnerList.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretOwnerList { +function Get-GitHubSecretOwnerList { <# .SYNOPSIS List organization secrets. @@ -46,13 +46,13 @@ function Get-GitHubSecretOwnerList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/secrets" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.secrets | ForEach-Object { $selectedRepositories = @() if ($_.visibility -eq 'selected') { diff --git a/src/functions/private/Secrets/Get-GitHubSecretRepositoryByName.ps1 b/src/functions/private/Secrets/Get-GitHubSecretRepositoryByName.ps1 index 756365337..19ddfba4e 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretRepositoryByName.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretRepositoryByName.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretRepositoryByName { +function Get-GitHubSecretRepositoryByName { <# .SYNOPSIS Get a repository secret. @@ -51,13 +51,13 @@ function Get-GitHubSecretRepositoryByName { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/secrets/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubSecret]::new($_.Response, $Owner, $Repository, $null, $null) } } diff --git a/src/functions/private/Secrets/Get-GitHubSecretRepositoryList.ps1 b/src/functions/private/Secrets/Get-GitHubSecretRepositoryList.ps1 index 4914a29d8..26501bd19 100644 --- a/src/functions/private/Secrets/Get-GitHubSecretRepositoryList.ps1 +++ b/src/functions/private/Secrets/Get-GitHubSecretRepositoryList.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubSecretRepositoryList { +function Get-GitHubSecretRepositoryList { <# .SYNOPSIS List repository secrets. @@ -60,13 +60,13 @@ function Get-GitHubSecretRepositoryList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/secrets" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.secrets | ForEach-Object { [GitHubSecret]::new($_, $Owner, $Repository, $null, $null) } diff --git a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnEnvironment.ps1 b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnEnvironment.ps1 index 0e359ae6a..0c0977b76 100644 --- a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnEnvironment.ps1 +++ b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnEnvironment.ps1 @@ -57,13 +57,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/secrets/public-key" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubPublicKey]::new($_.Response, 'actions', $Owner, $Repository, $Environment) } } diff --git a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnOrganization.ps1 b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnOrganization.ps1 index 9396d6797..6f6d799a8 100644 --- a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnOrganization.ps1 +++ b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnOrganization.ps1 @@ -50,13 +50,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/secrets/public-key" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubPublicKey]::new($_.Response, 'actions', $Owner, $null, $null) } } diff --git a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnRepository.ps1 b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnRepository.ps1 index 573fd6606..7812b8754 100644 --- a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnRepository.ps1 +++ b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForActionOnRepository.ps1 @@ -53,13 +53,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/secrets/public-key" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubPublicKey]::new($_.Response, 'actions', $Owner, $Repository, $null) } } diff --git a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnOrganization.ps1 b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnOrganization.ps1 index d8d246700..f93081abe 100644 --- a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnOrganization.ps1 +++ b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnOrganization.ps1 @@ -48,13 +48,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/codespaces/secrets/public-key" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubPublicKey]::new($_.Response, 'codespaces', $Owner, $null, $null) } } diff --git a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnRepository.ps1 b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnRepository.ps1 index 8a7f73276..a3ee90088 100644 --- a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnRepository.ps1 +++ b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnRepository.ps1 @@ -52,13 +52,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/codespaces/secrets/public-key" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubPublicKey]::new($_.Response, 'codespaces', $Owner, $Repository, $null) } } diff --git a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnUser.ps1 b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnUser.ps1 index b23a0ba96..27eb34411 100644 --- a/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnUser.ps1 +++ b/src/functions/private/Secrets/PublicKey/Get-GitHubPublicKeyForCodespacesOnUser.ps1 @@ -45,13 +45,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/codespaces/secrets/public-key' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubPublicKey]::new($_.Response, 'codespaces', $Context.UserName, $null, $null) } } diff --git a/src/functions/private/Secrets/Remove-GitHubSecretFromEnvironment.ps1 b/src/functions/private/Secrets/Remove-GitHubSecretFromEnvironment.ps1 index ef32f5e7f..a7838c887 100644 --- a/src/functions/private/Secrets/Remove-GitHubSecretFromEnvironment.ps1 +++ b/src/functions/private/Secrets/Remove-GitHubSecretFromEnvironment.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubSecretFromEnvironment { +function Remove-GitHubSecretFromEnvironment { <# .SYNOPSIS Delete an environment secret. @@ -47,14 +47,14 @@ function Remove-GitHubSecretFromEnvironment { } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/secrets/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("secret [$Name] on [$Owner/$Repository/$Environment]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Secrets/Remove-GitHubSecretFromOwner.ps1 b/src/functions/private/Secrets/Remove-GitHubSecretFromOwner.ps1 index c788c6c9b..7cdb07809 100644 --- a/src/functions/private/Secrets/Remove-GitHubSecretFromOwner.ps1 +++ b/src/functions/private/Secrets/Remove-GitHubSecretFromOwner.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubSecretFromOwner { +function Remove-GitHubSecretFromOwner { <# .SYNOPSIS Delete an organization secret. @@ -40,14 +40,14 @@ function Remove-GitHubSecretFromOwner { } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("secret [$Name] on [$Owner]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Secrets/Remove-GitHubSecretFromRepository.ps1 b/src/functions/private/Secrets/Remove-GitHubSecretFromRepository.ps1 index d029c8705..a6cce0757 100644 --- a/src/functions/private/Secrets/Remove-GitHubSecretFromRepository.ps1 +++ b/src/functions/private/Secrets/Remove-GitHubSecretFromRepository.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubSecretFromRepository { +function Remove-GitHubSecretFromRepository { <# .SYNOPSIS Delete a repository secret. @@ -43,14 +43,14 @@ function Remove-GitHubSecretFromRepository { } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/actions/secrets/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("secret [$Name] on [$Owner/$Repository]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Secrets/Set-GitHubSecretOnEnvironment.ps1 b/src/functions/private/Secrets/Set-GitHubSecretOnEnvironment.ps1 index c4d2549a5..1631f4c88 100644 --- a/src/functions/private/Secrets/Set-GitHubSecretOnEnvironment.ps1 +++ b/src/functions/private/Secrets/Set-GitHubSecretOnEnvironment.ps1 @@ -1,4 +1,4 @@ -function Set-GitHubSecretOnEnvironment { +function Set-GitHubSecretOnEnvironment { <# .SYNOPSIS Create or update an environment secret. @@ -71,7 +71,7 @@ function Set-GitHubSecretOnEnvironment { key_id = $KeyID } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/secrets/$Name" Body = $body @@ -79,7 +79,7 @@ function Set-GitHubSecretOnEnvironment { } if ($PSCmdlet.ShouldProcess("secret [$Name] on [$Owner/$Repository/$Environment]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Secrets/Set-GitHubSecretOnOwner.ps1 b/src/functions/private/Secrets/Set-GitHubSecretOnOwner.ps1 index 8d4c5f16e..705c87672 100644 --- a/src/functions/private/Secrets/Set-GitHubSecretOnOwner.ps1 +++ b/src/functions/private/Secrets/Set-GitHubSecretOnOwner.ps1 @@ -1,4 +1,4 @@ -function Set-GitHubSecretOnOwner { +function Set-GitHubSecretOnOwner { <# .SYNOPSIS Create or update an organization secret. @@ -78,7 +78,7 @@ function Set-GitHubSecretOnOwner { $body['selected_repository_ids'] = $SelectedRepositories } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name" Body = $body @@ -86,7 +86,7 @@ function Set-GitHubSecretOnOwner { } if ($PSCmdlet.ShouldProcess("secret [$Name] on [$Owner]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Secrets/Set-GitHubSecretOnRepository.ps1 b/src/functions/private/Secrets/Set-GitHubSecretOnRepository.ps1 index 075ae07da..4ae7efdb1 100644 --- a/src/functions/private/Secrets/Set-GitHubSecretOnRepository.ps1 +++ b/src/functions/private/Secrets/Set-GitHubSecretOnRepository.ps1 @@ -1,4 +1,4 @@ -function Set-GitHubSecretOnRepository { +function Set-GitHubSecretOnRepository { <# .SYNOPSIS Create or update a repository secret. @@ -59,7 +59,7 @@ function Set-GitHubSecretOnRepository { key_id = $KeyID } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Repository/actions/secrets/$Name" Body = $body @@ -67,7 +67,7 @@ function Set-GitHubSecretOnRepository { } if ($PSCmdlet.ShouldProcess("secret [$Name] on [$Owner/$Repository]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 b/src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 index abab4ded6..0b4b10245 100644 --- a/src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 @@ -38,13 +38,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/teams/$Slug" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubTeam]::new($_.Response, $Organization) } } diff --git a/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 index cc9874234..7060a63c8 100644 --- a/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 @@ -36,13 +36,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/teams" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($team in $_.Response) { [GitHubTeam]::new($team, $Organization) } diff --git a/src/functions/private/Teams/Get-GitHubTeamListByRepo.ps1 b/src/functions/private/Teams/Get-GitHubTeamListByRepo.ps1 index c08ae0015..f01f277f1 100644 --- a/src/functions/private/Teams/Get-GitHubTeamListByRepo.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamListByRepo.ps1 @@ -50,13 +50,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/teams" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($team in $_.Response) { [GitHubTeam]::new($team, $Organization) } diff --git a/src/functions/private/Users/Blocking/Block-GitHubUserByUser.ps1 b/src/functions/private/Users/Blocking/Block-GitHubUserByUser.ps1 index 5ded734db..5333cc35a 100644 --- a/src/functions/private/Users/Blocking/Block-GitHubUserByUser.ps1 +++ b/src/functions/private/Users/Blocking/Block-GitHubUserByUser.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/user/blocks/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Users/Blocking/Get-GitHubBlockedUserByUser.ps1 b/src/functions/private/Users/Blocking/Get-GitHubBlockedUserByUser.ps1 index 14ff2fabd..617a42038 100644 --- a/src/functions/private/Users/Blocking/Get-GitHubBlockedUserByUser.ps1 +++ b/src/functions/private/Users/Blocking/Get-GitHubBlockedUserByUser.ps1 @@ -34,14 +34,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/blocks' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Blocking/Test-GitHubBlockedUserByUser.ps1 b/src/functions/private/Users/Blocking/Test-GitHubBlockedUserByUser.ps1 index 13947ca01..ee8eaf8ff 100644 --- a/src/functions/private/Users/Blocking/Test-GitHubBlockedUserByUser.ps1 +++ b/src/functions/private/Users/Blocking/Test-GitHubBlockedUserByUser.ps1 @@ -46,14 +46,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/user/blocks/$Username" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Users/Blocking/Unblock-GitHubUserByUser.ps1 b/src/functions/private/Users/Blocking/Unblock-GitHubUserByUser.ps1 index 1a476643d..f4270adc8 100644 --- a/src/functions/private/Users/Blocking/Unblock-GitHubUserByUser.ps1 +++ b/src/functions/private/Users/Blocking/Unblock-GitHubUserByUser.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/user/blocks/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Users/Emails/Get-GitHubUserAllEmail.ps1 b/src/functions/private/Users/Emails/Get-GitHubUserAllEmail.ps1 index 74b7b21af..7a1167828 100644 --- a/src/functions/private/Users/Emails/Get-GitHubUserAllEmail.ps1 +++ b/src/functions/private/Users/Emails/Get-GitHubUserAllEmail.ps1 @@ -36,14 +36,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/emails' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Emails/Get-GitHubUserPublicEmail.ps1 b/src/functions/private/Users/Emails/Get-GitHubUserPublicEmail.ps1 index 568c3d93d..f5e67b6f0 100644 --- a/src/functions/private/Users/Emails/Get-GitHubUserPublicEmail.ps1 +++ b/src/functions/private/Users/Emails/Get-GitHubUserPublicEmail.ps1 @@ -38,14 +38,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/public_emails' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Followers/Get-GitHubUserFollowersOfUser.ps1 b/src/functions/private/Users/Followers/Get-GitHubUserFollowersOfUser.ps1 index 651c3cffe..abd3a7431 100644 --- a/src/functions/private/Users/Followers/Get-GitHubUserFollowersOfUser.ps1 +++ b/src/functions/private/Users/Followers/Get-GitHubUserFollowersOfUser.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/followers" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Followers/Get-GitHubUserFollowingMe.ps1 b/src/functions/private/Users/Followers/Get-GitHubUserFollowingMe.ps1 index 0664785b2..15509b6cc 100644 --- a/src/functions/private/Users/Followers/Get-GitHubUserFollowingMe.ps1 +++ b/src/functions/private/Users/Followers/Get-GitHubUserFollowingMe.ps1 @@ -35,14 +35,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/following' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Followers/Get-GitHubUserFollowingUser.ps1 b/src/functions/private/Users/Followers/Get-GitHubUserFollowingUser.ps1 index 0618427b9..c75ff3e0b 100644 --- a/src/functions/private/Users/Followers/Get-GitHubUserFollowingUser.ps1 +++ b/src/functions/private/Users/Followers/Get-GitHubUserFollowingUser.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/following" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Followers/Get-GitHubUserMyFollower.ps1 b/src/functions/private/Users/Followers/Get-GitHubUserMyFollower.ps1 index 9b4de061e..e2244e1d7 100644 --- a/src/functions/private/Users/Followers/Get-GitHubUserMyFollower.ps1 +++ b/src/functions/private/Users/Followers/Get-GitHubUserMyFollower.ps1 @@ -39,14 +39,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/followers' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Followers/Test-GitHubUserFollowedByMe.ps1 b/src/functions/private/Users/Followers/Test-GitHubUserFollowedByMe.ps1 index 5b9c2eb3a..c196d68c8 100644 --- a/src/functions/private/Users/Followers/Test-GitHubUserFollowedByMe.ps1 +++ b/src/functions/private/Users/Followers/Test-GitHubUserFollowedByMe.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/user/following/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Users/Followers/Test-GitHubUserFollowedByUser.ps1 b/src/functions/private/Users/Followers/Test-GitHubUserFollowedByUser.ps1 index 711d6bd38..56ab102f8 100644 --- a/src/functions/private/Users/Followers/Test-GitHubUserFollowedByUser.ps1 +++ b/src/functions/private/Users/Followers/Test-GitHubUserFollowedByUser.ps1 @@ -45,13 +45,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/following/$Follows" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/private/Users/GPG-Keys/Get-GitHubUserGpgKeyForUser.ps1 b/src/functions/private/Users/GPG-Keys/Get-GitHubUserGpgKeyForUser.ps1 index 49a2d0671..826bc9d9b 100644 --- a/src/functions/private/Users/GPG-Keys/Get-GitHubUserGpgKeyForUser.ps1 +++ b/src/functions/private/Users/GPG-Keys/Get-GitHubUserGpgKeyForUser.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/gpg_keys" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKey.ps1 b/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKey.ps1 index 6e43c8912..6b9ecbde3 100644 --- a/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKey.ps1 +++ b/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKey.ps1 @@ -37,14 +37,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/gpg_keys' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKeyById.ps1 b/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKeyById.ps1 index b08e22e64..62594cd6e 100644 --- a/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKeyById.ps1 +++ b/src/functions/private/Users/GPG-Keys/Get-GitHubUserMyGpgKeyById.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/user/gpg_keys/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Get-GitHubAllUser.ps1 b/src/functions/private/Users/Get-GitHubAllUser.ps1 index ea8233a2e..4d5f3c849 100644 --- a/src/functions/private/Users/Get-GitHubAllUser.ps1 +++ b/src/functions/private/Users/Get-GitHubAllUser.ps1 @@ -49,7 +49,7 @@ since = $Since } - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/users' Body = $body @@ -57,7 +57,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($account in $_.Response) { if ($account.type -eq 'Organization') { [GitHubOrganization]::New($account, $Context) diff --git a/src/functions/private/Users/Get-GitHubMyUser.ps1 b/src/functions/private/Users/Get-GitHubMyUser.ps1 index 6141d5043..af5308aed 100644 --- a/src/functions/private/Users/Get-GitHubMyUser.ps1 +++ b/src/functions/private/Users/Get-GitHubMyUser.ps1 @@ -36,13 +36,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { if ($_.Response.type -eq 'Organization') { [GitHubOrganization]::New($_.Response, $Context) } elseif ($_.Response.type -eq 'User') { diff --git a/src/functions/private/Users/Get-GitHubUserByName.ps1 b/src/functions/private/Users/Get-GitHubUserByName.ps1 index 880b63e55..ae3e644af 100644 --- a/src/functions/private/Users/Get-GitHubUserByName.ps1 +++ b/src/functions/private/Users/Get-GitHubUserByName.ps1 @@ -53,14 +53,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Name" Context = $Context } try { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { if ($_.Response.type -eq 'Organization') { [GitHubOrganization]::New($_.Response, $Context) } elseif ($_.Response.type -eq 'User') { diff --git a/src/functions/private/Users/Keys/Get-GitHubUserKeyForUser.ps1 b/src/functions/private/Users/Keys/Get-GitHubUserKeyForUser.ps1 index fe8e45150..2bab33bb4 100644 --- a/src/functions/private/Users/Keys/Get-GitHubUserKeyForUser.ps1 +++ b/src/functions/private/Users/Keys/Get-GitHubUserKeyForUser.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/keys" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Keys/Get-GitHubUserMyKey.ps1 b/src/functions/private/Users/Keys/Get-GitHubUserMyKey.ps1 index bbb59e5c7..305e86323 100644 --- a/src/functions/private/Users/Keys/Get-GitHubUserMyKey.ps1 +++ b/src/functions/private/Users/Keys/Get-GitHubUserMyKey.ps1 @@ -37,14 +37,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/keys' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Keys/Get-GitHubUserMyKeyById.ps1 b/src/functions/private/Users/Keys/Get-GitHubUserMyKeyById.ps1 index b46ce6ad7..41e32fb4a 100644 --- a/src/functions/private/Users/Keys/Get-GitHubUserMyKeyById.ps1 +++ b/src/functions/private/Users/Keys/Get-GitHubUserMyKeyById.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/user/keys/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKey.ps1 b/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKey.ps1 index e1a87c449..a74b4ea19 100644 --- a/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKey.ps1 +++ b/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKey.ps1 @@ -37,14 +37,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/ssh_signing_keys' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKeyById.ps1 b/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKeyById.ps1 index 34b13c546..c2571f0e5 100644 --- a/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKeyById.ps1 +++ b/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserMySigningKeyById.ps1 @@ -41,13 +41,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/user/ssh_signing_keys/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserSigningKeyForUser.ps1 b/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserSigningKeyForUser.ps1 index ae39b0a41..b17735e9e 100644 --- a/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserSigningKeyForUser.ps1 +++ b/src/functions/private/Users/SSH-Signing-Keys/Get-GitHubUserSigningKeyForUser.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/ssh_signing_keys" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Social-Accounts/Get-GitHubMyUserSocials.ps1 b/src/functions/private/Users/Social-Accounts/Get-GitHubMyUserSocials.ps1 index ddb1e7c30..1f4eee04f 100644 --- a/src/functions/private/Users/Social-Accounts/Get-GitHubMyUserSocials.ps1 +++ b/src/functions/private/Users/Social-Accounts/Get-GitHubMyUserSocials.ps1 @@ -35,14 +35,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/user/social_accounts' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Users/Social-Accounts/Get-GitHubUserSocialsByName.ps1 b/src/functions/private/Users/Social-Accounts/Get-GitHubUserSocialsByName.ps1 index 876314349..acaea233b 100644 --- a/src/functions/private/Users/Social-Accounts/Get-GitHubUserSocialsByName.ps1 +++ b/src/functions/private/Users/Social-Accounts/Get-GitHubUserSocialsByName.ps1 @@ -39,13 +39,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/users/$Username/social_accounts" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/private/Variables/Get-GitHubVariableEnvironmentByName.ps1 b/src/functions/private/Variables/Get-GitHubVariableEnvironmentByName.ps1 index 13525ad59..69812c051 100644 --- a/src/functions/private/Variables/Get-GitHubVariableEnvironmentByName.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableEnvironmentByName.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableEnvironmentByName { +function Get-GitHubVariableEnvironmentByName { <# .SYNOPSIS Retrieves a specific variable from a GitHub repository. @@ -64,13 +64,13 @@ function Get-GitHubVariableEnvironmentByName { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/variables/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubVariable]::new($_.Response, $Owner, $Repository, $Environment, $null) } } diff --git a/src/functions/private/Variables/Get-GitHubVariableEnvironmentList.ps1 b/src/functions/private/Variables/Get-GitHubVariableEnvironmentList.ps1 index c66ee2a83..a3241f63c 100644 --- a/src/functions/private/Variables/Get-GitHubVariableEnvironmentList.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableEnvironmentList.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableEnvironmentList { +function Get-GitHubVariableEnvironmentList { <# .SYNOPSIS Retrieves all variables for a specified environment in a GitHub repository. @@ -66,13 +66,13 @@ function Get-GitHubVariableEnvironmentList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/variables" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.variables | ForEach-Object { [GitHubVariable]::new($_, $Owner, $Repository, $Environment, $null) } diff --git a/src/functions/private/Variables/Get-GitHubVariableFromOrganization.ps1 b/src/functions/private/Variables/Get-GitHubVariableFromOrganization.ps1 index b8336dbc5..74b0cd0b3 100644 --- a/src/functions/private/Variables/Get-GitHubVariableFromOrganization.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableFromOrganization.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableFromOrganization { +function Get-GitHubVariableFromOrganization { <# .SYNOPSIS List repository organization variables. @@ -84,7 +84,7 @@ function Get-GitHubVariableFromOrganization { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/organization-variables" PerPage = $PerPage @@ -92,7 +92,7 @@ function Get-GitHubVariableFromOrganization { } try { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.variables | ForEach-Object { [GitHubVariable]::new($_, $Owner, $null, $null, $null) } diff --git a/src/functions/private/Variables/Get-GitHubVariableOwnerByName.ps1 b/src/functions/private/Variables/Get-GitHubVariableOwnerByName.ps1 index 8b60db7db..a222c70d7 100644 --- a/src/functions/private/Variables/Get-GitHubVariableOwnerByName.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableOwnerByName.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableOwnerByName { +function Get-GitHubVariableOwnerByName { <# .SYNOPSIS Get an organization variable. @@ -54,13 +54,13 @@ function Get-GitHubVariableOwnerByName { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/variables/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $selectedRepositories = @() if ($_.Response.visibility -eq 'selected') { $selectedRepositories = Get-GitHubVariableSelectedRepository -Owner $Owner -Name $_.Response.name -Context $Context diff --git a/src/functions/private/Variables/Get-GitHubVariableOwnerList.ps1 b/src/functions/private/Variables/Get-GitHubVariableOwnerList.ps1 index 08767d625..892ad9eff 100644 --- a/src/functions/private/Variables/Get-GitHubVariableOwnerList.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableOwnerList.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableOwnerList { +function Get-GitHubVariableOwnerList { <# .SYNOPSIS List organization variables @@ -77,13 +77,13 @@ function Get-GitHubVariableOwnerList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/variables" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.variables | ForEach-Object { $selectedRepositories = @() if ($_.visibility -eq 'selected') { diff --git a/src/functions/private/Variables/Get-GitHubVariableRepositoryByName.ps1 b/src/functions/private/Variables/Get-GitHubVariableRepositoryByName.ps1 index a1a23457a..20865a359 100644 --- a/src/functions/private/Variables/Get-GitHubVariableRepositoryByName.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableRepositoryByName.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableRepositoryByName { +function Get-GitHubVariableRepositoryByName { <# .SYNOPSIS Get a repository variable @@ -53,13 +53,13 @@ function Get-GitHubVariableRepositoryByName { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/variables/$Name" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubVariable]::new($_.Response, $Owner, $Repository, $null, $null) } } diff --git a/src/functions/private/Variables/Get-GitHubVariableRepositoryList.ps1 b/src/functions/private/Variables/Get-GitHubVariableRepositoryList.ps1 index ff2e39cb6..d38e51eec 100644 --- a/src/functions/private/Variables/Get-GitHubVariableRepositoryList.ps1 +++ b/src/functions/private/Variables/Get-GitHubVariableRepositoryList.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubVariableRepositoryList { +function Get-GitHubVariableRepositoryList { <# .SYNOPSIS List repository variables. @@ -62,13 +62,13 @@ function Get-GitHubVariableRepositoryList { } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/variables" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.variables | ForEach-Object { [GitHubVariable]::new($_, $Owner, $Repository, $null, $null) } diff --git a/src/functions/private/Variables/New-GitHubVariableOnEnvironment.ps1 b/src/functions/private/Variables/New-GitHubVariableOnEnvironment.ps1 index 607282a45..8b3f764ec 100644 --- a/src/functions/private/Variables/New-GitHubVariableOnEnvironment.ps1 +++ b/src/functions/private/Variables/New-GitHubVariableOnEnvironment.ps1 @@ -1,4 +1,4 @@ -function New-GitHubVariableOnEnvironment { +function New-GitHubVariableOnEnvironment { <# .SYNOPSIS Create an environment variable. @@ -65,7 +65,7 @@ function New-GitHubVariableOnEnvironment { value = $Value } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/variables" Body = $body @@ -73,7 +73,7 @@ function New-GitHubVariableOnEnvironment { } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner/$Repository/$Environment]", 'Create')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/New-GitHubVariableOnOwner.ps1 b/src/functions/private/Variables/New-GitHubVariableOnOwner.ps1 index e705f543d..5ba36f62e 100644 --- a/src/functions/private/Variables/New-GitHubVariableOnOwner.ps1 +++ b/src/functions/private/Variables/New-GitHubVariableOnOwner.ps1 @@ -1,4 +1,4 @@ -function New-GitHubVariableOnOwner { +function New-GitHubVariableOnOwner { <# .SYNOPSIS Create an organization variable. @@ -72,7 +72,7 @@ function New-GitHubVariableOnOwner { $body['selected_repository_ids'] = $SelectedRepositories } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/orgs/$Owner/actions/variables" Body = $body @@ -80,7 +80,7 @@ function New-GitHubVariableOnOwner { } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner]", 'Create')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/New-GitHubVariableOnRepository.ps1 b/src/functions/private/Variables/New-GitHubVariableOnRepository.ps1 index 774d65826..32899700f 100644 --- a/src/functions/private/Variables/New-GitHubVariableOnRepository.ps1 +++ b/src/functions/private/Variables/New-GitHubVariableOnRepository.ps1 @@ -1,4 +1,4 @@ -function New-GitHubVariableOnRepository { +function New-GitHubVariableOnRepository { <# .SYNOPSIS Create a repository variable. @@ -53,7 +53,7 @@ function New-GitHubVariableOnRepository { value = $Value } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/actions/variables" Body = $body @@ -61,7 +61,7 @@ function New-GitHubVariableOnRepository { } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner/$Repository]", 'Create')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/Remove-GitHubVariableFromEnvironment.ps1 b/src/functions/private/Variables/Remove-GitHubVariableFromEnvironment.ps1 index bb8fc08f2..f09b9fc8a 100644 --- a/src/functions/private/Variables/Remove-GitHubVariableFromEnvironment.ps1 +++ b/src/functions/private/Variables/Remove-GitHubVariableFromEnvironment.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubVariableFromEnvironment { +function Remove-GitHubVariableFromEnvironment { <# .SYNOPSIS Delete an environment variable. @@ -48,14 +48,14 @@ function Remove-GitHubVariableFromEnvironment { } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/variables/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner/$Repository/$Environment]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/Remove-GitHubVariableFromOwner.ps1 b/src/functions/private/Variables/Remove-GitHubVariableFromOwner.ps1 index bfa1df9ac..885416444 100644 --- a/src/functions/private/Variables/Remove-GitHubVariableFromOwner.ps1 +++ b/src/functions/private/Variables/Remove-GitHubVariableFromOwner.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubVariableFromOwner { +function Remove-GitHubVariableFromOwner { <# .SYNOPSIS Delete an organization variable. @@ -41,14 +41,14 @@ function Remove-GitHubVariableFromOwner { } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Owner/actions/variables/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/Remove-GitHubVariableFromRepository.ps1 b/src/functions/private/Variables/Remove-GitHubVariableFromRepository.ps1 index 0cf9c7ec2..3822bb9ba 100644 --- a/src/functions/private/Variables/Remove-GitHubVariableFromRepository.ps1 +++ b/src/functions/private/Variables/Remove-GitHubVariableFromRepository.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubVariableFromRepository { +function Remove-GitHubVariableFromRepository { <# .SYNOPSIS Delete a repository variable. @@ -44,14 +44,14 @@ function Remove-GitHubVariableFromRepository { } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/actions/variables/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner/$Repository]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/Update-GitHubVariableOnEnvironment.ps1 b/src/functions/private/Variables/Update-GitHubVariableOnEnvironment.ps1 index 568f43d9d..53a21c906 100644 --- a/src/functions/private/Variables/Update-GitHubVariableOnEnvironment.ps1 +++ b/src/functions/private/Variables/Update-GitHubVariableOnEnvironment.ps1 @@ -1,4 +1,4 @@ -function Update-GitHubVariableOnEnvironment { +function Update-GitHubVariableOnEnvironment { <# .SYNOPSIS Update an environment variable. @@ -73,7 +73,7 @@ function Update-GitHubVariableOnEnvironment { $body.value = $Value } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/repos/$Owner/$Repository/environments/$Environment/variables/$Name" Body = $body @@ -81,7 +81,7 @@ function Update-GitHubVariableOnEnvironment { } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner/$Repository/$Environment]", 'Update')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/Update-GitHubVariableOnOwner.ps1 b/src/functions/private/Variables/Update-GitHubVariableOnOwner.ps1 index fc8d5d60f..3463b8b87 100644 --- a/src/functions/private/Variables/Update-GitHubVariableOnOwner.ps1 +++ b/src/functions/private/Variables/Update-GitHubVariableOnOwner.ps1 @@ -1,4 +1,4 @@ -function Update-GitHubVariableOnOwner { +function Update-GitHubVariableOnOwner { <# .SYNOPSIS Update an organization variable. @@ -84,7 +84,7 @@ function Update-GitHubVariableOnOwner { $body['selected_repository_ids'] = $SelectedRepositories } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/orgs/$Owner/actions/variables/$Name" Body = $body @@ -92,7 +92,7 @@ function Update-GitHubVariableOnOwner { } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner]", 'Update')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Variables/Update-GitHubVariableOnRepository.ps1 b/src/functions/private/Variables/Update-GitHubVariableOnRepository.ps1 index 3e1e59b42..d35bd664e 100644 --- a/src/functions/private/Variables/Update-GitHubVariableOnRepository.ps1 +++ b/src/functions/private/Variables/Update-GitHubVariableOnRepository.ps1 @@ -1,4 +1,4 @@ -function Update-GitHubVariableOnRepository { +function Update-GitHubVariableOnRepository { <# .SYNOPSIS Update a repository variable. @@ -60,7 +60,7 @@ function Update-GitHubVariableOnRepository { $body.value = $Value } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/repos/$Owner/$Repository/actions/variables/$Name" Body = $body @@ -68,7 +68,7 @@ function Update-GitHubVariableOnRepository { } if ($PSCmdlet.ShouldProcess("variable [$Name] on [$Owner/$Repository]", 'Update')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByID.ps1 b/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByID.ps1 index 042cfc640..a9aab7b78 100644 --- a/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByID.ps1 +++ b/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByID.ps1 @@ -40,13 +40,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/app/hook/deliveries/$ID" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubWebhookDelivery]::new($_.Response) } } diff --git a/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByList.ps1 b/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByList.ps1 index e418768af..8f0dac867 100644 --- a/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByList.ps1 +++ b/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryByList.ps1 @@ -39,14 +39,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/app/hook/deliveries' PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response | ForEach-Object { [GitHubWebhookDelivery]@{ ID = $_.id diff --git a/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 b/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 index 1c62e85a8..4c62a1ac5 100644 --- a/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 +++ b/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 @@ -44,7 +44,7 @@ variables = $Variables } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/graphql' Body = $body @@ -52,7 +52,7 @@ } try { - $apiResponse = Invoke-GitHubAPI @inputObject + $apiResponse = Invoke-GitHubAPI @apiParams $graphQLResponse = $apiResponse.Response # Handle GraphQL-specific errors (200 OK with errors in response) if ($graphQLResponse.errors) { diff --git a/src/functions/public/Apps/GitHub App Installations/Add-GitHubAppInstallationRepositoryAccess.ps1 b/src/functions/public/Apps/GitHub App Installations/Add-GitHubAppInstallationRepositoryAccess.ps1 index 50086f504..b447032cb 100644 --- a/src/functions/public/Apps/GitHub App Installations/Add-GitHubAppInstallationRepositoryAccess.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Add-GitHubAppInstallationRepositoryAccess.ps1 @@ -70,7 +70,7 @@ repositories = $Repositories } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations/$ID/repositories/add" Body = $body @@ -78,7 +78,7 @@ } if ($PSCmdlet.ShouldProcess("$Enterprise/$Organization", 'Add repo access to installation')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppAccessibleRepository.ps1 b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppAccessibleRepository.ps1 index c010bc146..a884c9083 100644 --- a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppAccessibleRepository.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppAccessibleRepository.ps1 @@ -61,14 +61,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/enterprises/$Enterprise/apps/installable_organizations/$Organization/accessible_repositories" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($repo in $_.Response) { [GitHubRepository]@{ ID = $repo.id diff --git a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallationRepositoryAccess.ps1 b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallationRepositoryAccess.ps1 index e54f6d663..0c6423e19 100644 --- a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallationRepositoryAccess.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallationRepositoryAccess.ps1 @@ -67,14 +67,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations/$ID/repositories" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Apps/GitHub App Installations/Remove-GitHubAppInstallationRepositoryAccess.ps1 b/src/functions/public/Apps/GitHub App Installations/Remove-GitHubAppInstallationRepositoryAccess.ps1 index 3d0097fa8..9c604ab1b 100644 --- a/src/functions/public/Apps/GitHub App Installations/Remove-GitHubAppInstallationRepositoryAccess.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Remove-GitHubAppInstallationRepositoryAccess.ps1 @@ -70,7 +70,7 @@ repositories = $Repositories } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations/$ID/repositories/remove" Body = $body @@ -78,7 +78,7 @@ } if ($PSCmdlet.ShouldProcess("$Enterprise/$Organization - $Repositories", 'Remove repository access')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Apps/GitHub App Installations/Update-GitHubAppInstallationRepositoryAccess.ps1 b/src/functions/public/Apps/GitHub App Installations/Update-GitHubAppInstallationRepositoryAccess.ps1 index cd6b9905b..58111e114 100644 --- a/src/functions/public/Apps/GitHub App Installations/Update-GitHubAppInstallationRepositoryAccess.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Update-GitHubAppInstallationRepositoryAccess.ps1 @@ -85,7 +85,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/enterprises/$Enterprise/apps/organizations/$Organization/installations/$ID/repositories" Body = $body @@ -93,7 +93,7 @@ } if ($PSCmdlet.ShouldProcess("$Enterprise/$Organization", 'Update repository access')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Apps/GitHub App/Get-GitHubAppInstallationRequest.ps1 b/src/functions/public/Apps/GitHub App/Get-GitHubAppInstallationRequest.ps1 index 006451ab6..7f9da82ce 100644 --- a/src/functions/public/Apps/GitHub App/Get-GitHubAppInstallationRequest.ps1 +++ b/src/functions/public/Apps/GitHub App/Get-GitHubAppInstallationRequest.ps1 @@ -37,13 +37,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/app/installation-requests' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response | ForEach-Object { [GitHubAppInstallationRequest]::new($_) } diff --git a/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 b/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 index ca705b122..aa11d5811 100644 --- a/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 +++ b/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 @@ -59,14 +59,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/actions/artifacts/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess("artifact [$Owner/$Repository/$ID]", 'Remove')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Artifacts/Save-GitHubArtifact.ps1 b/src/functions/public/Artifacts/Save-GitHubArtifact.ps1 index dfadd17df..6c34f001d 100644 --- a/src/functions/public/Artifacts/Save-GitHubArtifact.ps1 +++ b/src/functions/public/Artifacts/Save-GitHubArtifact.ps1 @@ -99,13 +99,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/artifacts/$ID/zip" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $headers = $_.Headers $itemType = $Path.EndsWith('.zip') ? 'File' : 'Directory' $isAbsolute = [System.IO.Path]::IsPathRooted($Path) diff --git a/src/functions/public/Emojis/Get-GitHubEmoji.ps1 b/src/functions/public/Emojis/Get-GitHubEmoji.ps1 index 78602ffe6..ec00fba7e 100644 --- a/src/functions/public/Emojis/Get-GitHubEmoji.ps1 +++ b/src/functions/public/Emojis/Get-GitHubEmoji.ps1 @@ -50,13 +50,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/emojis' Context = $Context } - $response = Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty Response + $response = Invoke-GitHubAPI @apiParams | Select-Object -ExpandProperty Response switch ($PSCmdlet.ParameterSetName) { 'Download' { diff --git a/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 b/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 index 47b379e6d..a223d953f 100644 --- a/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 +++ b/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 @@ -49,14 +49,14 @@ process { $encodedName = [System.Uri]::EscapeDataString($Name) - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' Uri = $Context.ApiBaseUri + "/repos/$Owner/$Repository/environments/$encodedName" Context = $Context } if ($PSCmdlet.ShouldProcess("Environment [$Owner/$Repository/$Name]", 'Delete')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Environments/Set-GitHubEnvironment.ps1 b/src/functions/public/Environments/Set-GitHubEnvironment.ps1 index b048f185e..fe8992859 100644 --- a/src/functions/public/Environments/Set-GitHubEnvironment.ps1 +++ b/src/functions/public/Environments/Set-GitHubEnvironment.ps1 @@ -173,7 +173,7 @@ } $encodedName = [System.Uri]::EscapeDataString($Name) - $inputObject = @{ + $apiParams = @{ Method = 'PUT' Uri = $Context.ApiBaseUri + "/repos/$Owner/$Repository/environments/$encodedName" Body = $body @@ -181,7 +181,7 @@ } if ($PSCmdlet.ShouldProcess("Environment [$Owner/$Repository/$Name]", 'Set')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubEnvironment]::new($_.Response, $Owner, $Repository, $Context) } } diff --git a/src/functions/public/Markdown/Get-GitHubMarkdown.ps1 b/src/functions/public/Markdown/Get-GitHubMarkdown.ps1 index 3ba19ea1d..e04d5f538 100644 --- a/src/functions/public/Markdown/Get-GitHubMarkdown.ps1 +++ b/src/functions/public/Markdown/Get-GitHubMarkdown.ps1 @@ -63,14 +63,14 @@ text = $Text } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/markdown' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Markdown/Get-GitHubMarkdownRaw.ps1 b/src/functions/public/Markdown/Get-GitHubMarkdownRaw.ps1 index 54358242d..212815387 100644 --- a/src/functions/public/Markdown/Get-GitHubMarkdownRaw.ps1 +++ b/src/functions/public/Markdown/Get-GitHubMarkdownRaw.ps1 @@ -48,7 +48,7 @@ text = $Text } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/markdown/raw' ContentType = 'text/plain' @@ -56,7 +56,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Meta/Get-GitHubApiVersion.ps1 b/src/functions/public/Meta/Get-GitHubApiVersion.ps1 index e95f0b309..7a618a104 100644 --- a/src/functions/public/Meta/Get-GitHubApiVersion.ps1 +++ b/src/functions/public/Meta/Get-GitHubApiVersion.ps1 @@ -38,13 +38,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' ApiEndpoint = '/versions' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Meta/Get-GitHubMeta.ps1 b/src/functions/public/Meta/Get-GitHubMeta.ps1 index ad6a36efc..156523d2f 100644 --- a/src/functions/public/Meta/Get-GitHubMeta.ps1 +++ b/src/functions/public/Meta/Get-GitHubMeta.ps1 @@ -46,13 +46,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' ApiEndpoint = '/meta' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Meta/Get-GitHubOctocat.ps1 b/src/functions/public/Meta/Get-GitHubOctocat.ps1 index 600ff3268..ae2c8d438 100644 --- a/src/functions/public/Meta/Get-GitHubOctocat.ps1 +++ b/src/functions/public/Meta/Get-GitHubOctocat.ps1 @@ -51,14 +51,14 @@ s = $Saying } - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/octocat' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Meta/Get-GitHubRoot.ps1 b/src/functions/public/Meta/Get-GitHubRoot.ps1 index b38e36842..196782dcf 100644 --- a/src/functions/public/Meta/Get-GitHubRoot.ps1 +++ b/src/functions/public/Meta/Get-GitHubRoot.ps1 @@ -37,13 +37,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Meta/Get-GitHubZen.ps1 b/src/functions/public/Meta/Get-GitHubZen.ps1 index 274989e2e..7f2fbb7cc 100644 --- a/src/functions/public/Meta/Get-GitHubZen.ps1 +++ b/src/functions/public/Meta/Get-GitHubZen.ps1 @@ -37,13 +37,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/zen' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 b/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 index 2354b1fb0..9c51dda37 100644 --- a/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 +++ b/src/functions/public/Organization/Members/Get-GitHubOrganizationMember.ps1 @@ -58,7 +58,7 @@ role = $Role } - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/members" Body = $body @@ -66,7 +66,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($user in $_.Response) { [GitHubUser]::new($user) } diff --git a/src/functions/public/Organization/Members/Get-GitHubOrganizationPendingInvitation.ps1 b/src/functions/public/Organization/Members/Get-GitHubOrganizationPendingInvitation.ps1 index a3a423aae..3476a62c3 100644 --- a/src/functions/public/Organization/Members/Get-GitHubOrganizationPendingInvitation.ps1 +++ b/src/functions/public/Organization/Members/Get-GitHubOrganizationPendingInvitation.ps1 @@ -64,7 +64,7 @@ invitation_source = $InvitationSource } - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Organization/invitations" Body = $body @@ -72,7 +72,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Organization/Members/New-GitHubOrganizationInvitation.ps1 b/src/functions/public/Organization/Members/New-GitHubOrganizationInvitation.ps1 index 7f6b5015c..b1fb3633a 100644 --- a/src/functions/public/Organization/Members/New-GitHubOrganizationInvitation.ps1 +++ b/src/functions/public/Organization/Members/New-GitHubOrganizationInvitation.ps1 @@ -86,7 +86,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/orgs/$Organization/invitations" Body = $body @@ -94,7 +94,7 @@ } if ($PSCmdlet.ShouldProcess("$InviteeID$Email to organization $Organization", 'Invite')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Organization/Members/Remove-GitHubOrganizationInvitation.ps1 b/src/functions/public/Organization/Members/Remove-GitHubOrganizationInvitation.ps1 index de656a1aa..2b3192f3c 100644 --- a/src/functions/public/Organization/Members/Remove-GitHubOrganizationInvitation.ps1 +++ b/src/functions/public/Organization/Members/Remove-GitHubOrganizationInvitation.ps1 @@ -51,14 +51,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Organization/invitations/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess('GitHub Organization invitation', 'Remove')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Organization/Update-GitHubOrganization.ps1 b/src/functions/public/Organization/Update-GitHubOrganization.ps1 index 9095cf593..2315d6c90 100644 --- a/src/functions/public/Organization/Update-GitHubOrganization.ps1 +++ b/src/functions/public/Organization/Update-GitHubOrganization.ps1 @@ -195,7 +195,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/orgs/$Name" Body = $body @@ -203,7 +203,7 @@ } if ($PSCmdlet.ShouldProcess("organization [$Name]", 'Set')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubOrganization]::new($_.Response, $Context) } } diff --git a/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 b/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 index 3d3a193e1..8183619cd 100644 --- a/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 +++ b/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 @@ -54,13 +54,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/rate_limit' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.Resources.PSObject.Properties | ForEach-Object { [GitHubRateLimitResource]@{ Name = $_.Name diff --git a/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 index a713bad96..1986d386f 100644 --- a/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 @@ -172,7 +172,7 @@ } $uploadUrl = New-Uri @urlParams - $inputObject = @{ + $apiParams = @{ Method = 'POST' Uri = $uploadUrl ContentType = $ContentType @@ -180,7 +180,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubReleaseAsset]($_.Response) } } diff --git a/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 index 22e0c5f89..fccd994fd 100644 --- a/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 @@ -49,14 +49,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/releases/assets/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess("Asset with ID [$ID] in [$Owner/$Repository]", 'DELETE')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Releases/Assets/Save-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Save-GitHubReleaseAsset.ps1 index 038224750..575c8b7c3 100644 --- a/src/functions/public/Releases/Assets/Save-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Save-GitHubReleaseAsset.ps1 @@ -152,13 +152,13 @@ } # Now download the asset - $inputObject = @{ + $apiParams = @{ Method = 'GET' Uri = $asset.Url Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $itemType = $Path.EndsWith('.zip') ? 'File' : 'Directory' $isAbsolute = [System.IO.Path]::IsPathRooted($Path) $filename = $asset.Name diff --git a/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 index a632eaaef..d07cdfdc0 100644 --- a/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 @@ -74,7 +74,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/repos/$Owner/$Repository/releases/assets/$ID" Body = $body @@ -82,7 +82,7 @@ } if ($PSCmdlet.ShouldProcess("assets for release with ID [$ID] in [$Owner/$Repository]", 'Set')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubReleaseAsset]($_.Response) } } diff --git a/src/functions/public/Releases/New-GitHubRelease.ps1 b/src/functions/public/Releases/New-GitHubRelease.ps1 index 7d4c239fa..67aa10cf7 100644 --- a/src/functions/public/Releases/New-GitHubRelease.ps1 +++ b/src/functions/public/Releases/New-GitHubRelease.ps1 @@ -132,7 +132,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/releases" Body = $body @@ -140,7 +140,7 @@ } if ($PSCmdlet.ShouldProcess("$Owner/$Repository", 'Create a release')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRelease]::new($_.Response , $Owner, $Repository, $Latest) } } diff --git a/src/functions/public/Releases/New-GitHubReleaseNote.ps1 b/src/functions/public/Releases/New-GitHubReleaseNote.ps1 index 210789b9b..a81e18130 100644 --- a/src/functions/public/Releases/New-GitHubReleaseNote.ps1 +++ b/src/functions/public/Releases/New-GitHubReleaseNote.ps1 @@ -118,7 +118,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/releases/generate-notes" Body = $body @@ -126,7 +126,7 @@ } if ($PSCmdlet.ShouldProcess("release notes for release on $Owner/$Repository", 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [PSCustomObject]@{ Name = $_.Response.name Notes = $_.Response.body diff --git a/src/functions/public/Releases/Remove-GitHubRelease.ps1 b/src/functions/public/Releases/Remove-GitHubRelease.ps1 index 409e47711..babda52a4 100644 --- a/src/functions/public/Releases/Remove-GitHubRelease.ps1 +++ b/src/functions/public/Releases/Remove-GitHubRelease.ps1 @@ -53,14 +53,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/releases/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess("Release with ID [$ID] in [$Owner/$Repository]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Releases/Update-GitHubRelease.ps1 b/src/functions/public/Releases/Update-GitHubRelease.ps1 index 657fbbe0d..92d27100c 100644 --- a/src/functions/public/Releases/Update-GitHubRelease.ps1 +++ b/src/functions/public/Releases/Update-GitHubRelease.ps1 @@ -175,7 +175,7 @@ $body['draft'] = [bool]$Draft } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/repos/$Owner/$Repository/releases/$ID" Body = $body @@ -184,7 +184,7 @@ if ($PSCmdlet.ShouldProcess("release with ID [$ID] in [$Owner/$Repository]", 'Update')) { $resultLatest = $PSBoundParameters.ContainsKey('Latest') ? $Latest : $release.IsLatest - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRelease]::new($_.Response , $Owner, $Repository, $resultLatest) } } diff --git a/src/functions/public/Repositories/Autolinks/New-GitHubRepositoryAutolink.ps1 b/src/functions/public/Repositories/Autolinks/New-GitHubRepositoryAutolink.ps1 index 0e14196ef..bdfc0ce06 100644 --- a/src/functions/public/Repositories/Autolinks/New-GitHubRepositoryAutolink.ps1 +++ b/src/functions/public/Repositories/Autolinks/New-GitHubRepositoryAutolink.ps1 @@ -67,7 +67,7 @@ is_alphanumeric = $IsAlphanumeric } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/autolinks" Body = $body @@ -75,7 +75,7 @@ } if ($PSCmdlet.ShouldProcess("Autolink for repository [$Owner/$Repository]", 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Autolinks/Remove-GitHubRepositoryAutolink.ps1 b/src/functions/public/Repositories/Autolinks/Remove-GitHubRepositoryAutolink.ps1 index 27fcd6fcc..1e1b9b2cb 100644 --- a/src/functions/public/Repositories/Autolinks/Remove-GitHubRepositoryAutolink.ps1 +++ b/src/functions/public/Repositories/Autolinks/Remove-GitHubRepositoryAutolink.ps1 @@ -51,7 +51,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Repository/autolinks/$ID" Body = $body @@ -59,7 +59,7 @@ } if ($PSCmdlet.ShouldProcess("Autolink with ID [$ID] for repository [$Owner/$Repository]", 'DELETE')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/CustomProperties/Get-GitHubRepositoryCustomProperty.ps1 b/src/functions/public/Repositories/CustomProperties/Get-GitHubRepositoryCustomProperty.ps1 index 58b814718..f82e932f7 100644 --- a/src/functions/public/Repositories/CustomProperties/Get-GitHubRepositoryCustomProperty.ps1 +++ b/src/functions/public/Repositories/CustomProperties/Get-GitHubRepositoryCustomProperty.ps1 @@ -46,13 +46,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/properties/values" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Move-GitHubRepository.ps1 b/src/functions/public/Repositories/Move-GitHubRepository.ps1 index 599061245..204d24318 100644 --- a/src/functions/public/Repositories/Move-GitHubRepository.ps1 +++ b/src/functions/public/Repositories/Move-GitHubRepository.ps1 @@ -72,14 +72,14 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Name/transfer" Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubRepository]::New($_.Response) } } diff --git a/src/functions/public/Repositories/Permissions/Remove-GitHubRepositoryPermission.ps1 b/src/functions/public/Repositories/Permissions/Remove-GitHubRepositoryPermission.ps1 index 742e20b35..ba25d66e8 100644 --- a/src/functions/public/Repositories/Permissions/Remove-GitHubRepositoryPermission.ps1 +++ b/src/functions/public/Repositories/Permissions/Remove-GitHubRepositoryPermission.ps1 @@ -59,14 +59,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$TeamOwner/teams/$Team/repos/$Owner/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("Team [$TeamOwner/$Team] repository permission on [$Owner/$Name]", 'Remove')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Repositories/Permissions/Set-GitHubRepositoryPermission.ps1 b/src/functions/public/Repositories/Permissions/Set-GitHubRepositoryPermission.ps1 index f7ff1abee..a2ab0cbe6 100644 --- a/src/functions/public/Repositories/Permissions/Set-GitHubRepositoryPermission.ps1 +++ b/src/functions/public/Repositories/Permissions/Set-GitHubRepositoryPermission.ps1 @@ -102,7 +102,7 @@ permission = $Permission.ToLower() } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$TeamOwner/teams/$Team/repos/$Owner/$Name" Body = $body @@ -110,7 +110,7 @@ } if ($PSCmdlet.ShouldProcess("Team [$TeamOwner/$Team] repository permission [$Permission] on [$Owner/$Name]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Repositories/Remove-GitHubRepository.ps1 b/src/functions/public/Repositories/Remove-GitHubRepository.ps1 index 952211811..c96546fb3 100644 --- a/src/functions/public/Repositories/Remove-GitHubRepository.ps1 +++ b/src/functions/public/Repositories/Remove-GitHubRepository.ps1 @@ -47,14 +47,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Name" Context = $Context } if ($PSCmdlet.ShouldProcess("repo [$Owner/$Name]", 'Delete')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams Write-Verbose "Repository [$Owner/$Name] deleted." } } diff --git a/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 b/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 index d68a8969c..fcaccf936 100644 --- a/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 +++ b/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Name/private-vulnerability-reporting" Context = $Context } if ($PSCmdlet.ShouldProcess("Private Vulnerability Reporting for [$Owner/$Name]", 'Disable')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Disable-GitHubRepositorySecurityFix.ps1 b/src/functions/public/Repositories/Repositories/Disable-GitHubRepositorySecurityFix.ps1 index 66bf3a7c1..452365d86 100644 --- a/src/functions/public/Repositories/Repositories/Disable-GitHubRepositorySecurityFix.ps1 +++ b/src/functions/public/Repositories/Repositories/Disable-GitHubRepositorySecurityFix.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Name/automated-security-fixes" Context = $Context } if ($PSCmdlet.ShouldProcess("Security Fixes for [$Owner/$Name]", 'Disable')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryVulnerabilityAlert.ps1 b/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryVulnerabilityAlert.ps1 index e56f7d50b..3b43161d5 100644 --- a/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryVulnerabilityAlert.ps1 +++ b/src/functions/public/Repositories/Repositories/Disable-GitHubRepositoryVulnerabilityAlert.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/repos/$Owner/$Name/vulnerability-alerts" Context = $Context } if ($PSCmdlet.ShouldProcess("Vulnerability Alerts for [$Owner/$Name]", 'Disable')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 b/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 index 674d94cb0..d6bebba62 100644 --- a/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 +++ b/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryPrivateVulnerabilityReporting.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Name/private-vulnerability-reporting" Context = $Context } if ($PSCmdlet.ShouldProcess("Private Vulnerability Reporting for [$Owner/$Name]", 'Enable')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Enable-GitHubRepositorySecurityFix.ps1 b/src/functions/public/Repositories/Repositories/Enable-GitHubRepositorySecurityFix.ps1 index 4e3a04c5f..67fa2f94f 100644 --- a/src/functions/public/Repositories/Repositories/Enable-GitHubRepositorySecurityFix.ps1 +++ b/src/functions/public/Repositories/Repositories/Enable-GitHubRepositorySecurityFix.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Name/automated-security-fixes" Context = $Context } if ($PSCmdlet.ShouldProcess("Security Fixes for [$Owner/$Name]", 'Enable')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryVulnerabilityAlert.ps1 b/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryVulnerabilityAlert.ps1 index 09bb6f7f1..584ed3668 100644 --- a/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryVulnerabilityAlert.ps1 +++ b/src/functions/public/Repositories/Repositories/Enable-GitHubRepositoryVulnerabilityAlert.ps1 @@ -45,14 +45,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Name/vulnerability-alerts" Context = $Context } if ($PSCmdlet.ShouldProcess("Vulnerability Alerts for [$Owner/$Name]", 'Enable')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryActivity.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryActivity.ps1 index 283394912..e73fcf83d 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryActivity.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryActivity.ps1 @@ -129,7 +129,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/activity" Body = $body @@ -137,7 +137,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryCodeownersError.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryCodeownersError.ps1 index 6ce679aa2..20d8ae32f 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryCodeownersError.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryCodeownersError.ps1 @@ -57,14 +57,14 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/codeowners/errors" Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryContributor.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryContributor.ps1 index be517a48e..fe85303fd 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryContributor.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryContributor.ps1 @@ -61,7 +61,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/contributors" Body = $body @@ -69,7 +69,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryFork.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryFork.ps1 index 87bfe3c2d..d9d6ab9f9 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryFork.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryFork.ps1 @@ -57,7 +57,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/forks" Body = $body @@ -65,7 +65,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryLanguage.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryLanguage.ps1 index 9ac7934fc..19c67c1e0 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryLanguage.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryLanguage.ps1 @@ -45,13 +45,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/languages" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 index c26043b60..c1c190893 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositorySecurityFix.ps1 @@ -46,13 +46,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/automated-security-fixes" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTag.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTag.ps1 index 3bce11daf..c0b990b43 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTag.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTag.ps1 @@ -48,14 +48,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/tags" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTeam.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTeam.ps1 index a9bacc676..f448e6163 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTeam.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTeam.ps1 @@ -56,14 +56,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/teams" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTopic.ps1 b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTopic.ps1 index 8ef7f644b..b2a9aeabb 100644 --- a/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTopic.ps1 +++ b/src/functions/public/Repositories/Repositories/Get-GitHubRepositoryTopic.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/topics" PerPage = $PerPage Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response.names } } diff --git a/src/functions/public/Repositories/Repositories/Set-GitHubRepositoryTopic.ps1 b/src/functions/public/Repositories/Repositories/Set-GitHubRepositoryTopic.ps1 index 21230444e..93ca0c5b1 100644 --- a/src/functions/public/Repositories/Repositories/Set-GitHubRepositoryTopic.ps1 +++ b/src/functions/public/Repositories/Repositories/Set-GitHubRepositoryTopic.ps1 @@ -50,7 +50,7 @@ names = $Topic | ForEach-Object { $_.ToLower() } } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Name/topics" Body = $body @@ -58,7 +58,7 @@ } if ($PSCmdlet.ShouldProcess("topics for repo [$Owner/$Name]", 'Set')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response.names } } diff --git a/src/functions/public/Repositories/Repositories/Start-GitHubRepositoryEvent.ps1 b/src/functions/public/Repositories/Repositories/Start-GitHubRepositoryEvent.ps1 index ca5b19c3f..eb4fef843 100644 --- a/src/functions/public/Repositories/Repositories/Start-GitHubRepositoryEvent.ps1 +++ b/src/functions/public/Repositories/Repositories/Start-GitHubRepositoryEvent.ps1 @@ -83,14 +83,14 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Name/dispatches" Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Repositories/Repositories/Test-GitHubRepositoryVulnerabilityAlert.ps1 b/src/functions/public/Repositories/Repositories/Test-GitHubRepositoryVulnerabilityAlert.ps1 index 0fdaa1c1d..c4bf7ebaf 100644 --- a/src/functions/public/Repositories/Repositories/Test-GitHubRepositoryVulnerabilityAlert.ps1 +++ b/src/functions/public/Repositories/Repositories/Test-GitHubRepositoryVulnerabilityAlert.ps1 @@ -48,13 +48,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Name/vulnerability-alerts" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/public/Repositories/Update-GitHubRepository.ps1 b/src/functions/public/Repositories/Update-GitHubRepository.ps1 index d326e0321..615c1bb29 100644 --- a/src/functions/public/Repositories/Update-GitHubRepository.ps1 +++ b/src/functions/public/Repositories/Update-GitHubRepository.ps1 @@ -281,7 +281,7 @@ [pscustomobject]$body | Out-String -Stream | ForEach-Object { Write-Debug $_ } } if ($body.Keys.Count -gt 0) { - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/repos/$Owner/$Name" Body = $body @@ -289,7 +289,7 @@ } if ($PSCmdlet.ShouldProcess("Repository [$Owner/$Name]", 'Update')) { - $updatedRepo = Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty Response + $updatedRepo = Invoke-GitHubAPI @apiParams | Select-Object -ExpandProperty Response } if ($DebugPreference -eq 'Continue') { Write-Debug 'Repo has been updated' diff --git a/src/functions/public/Secrets/SelectedRepository/Add-GitHubSecretSelectedRepository.ps1 b/src/functions/public/Secrets/SelectedRepository/Add-GitHubSecretSelectedRepository.ps1 index a6f8f4f74..56ed38a60 100644 --- a/src/functions/public/Secrets/SelectedRepository/Add-GitHubSecretSelectedRepository.ps1 +++ b/src/functions/public/Secrets/SelectedRepository/Add-GitHubSecretSelectedRepository.ps1 @@ -67,13 +67,13 @@ Write-Debug 'Repo is already selected, returning' return } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name/repositories/$RepositoryID" Context = $Context } - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/public/Secrets/SelectedRepository/Get-GitHubSecretSelectedRepository.ps1 b/src/functions/public/Secrets/SelectedRepository/Get-GitHubSecretSelectedRepository.ps1 index fe814b412..21c00582d 100644 --- a/src/functions/public/Secrets/SelectedRepository/Get-GitHubSecretSelectedRepository.ps1 +++ b/src/functions/public/Secrets/SelectedRepository/Get-GitHubSecretSelectedRepository.ps1 @@ -72,13 +72,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name/repositories" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.repositories | ForEach-Object { [GitHubRepository]::New($_) } diff --git a/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 b/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 index 446259266..4306b7fab 100644 --- a/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 +++ b/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 @@ -66,14 +66,14 @@ Write-Debug 'Repo is not selected, returning' return } - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name/repositories/$RepositoryID" Context = $Context } if ($PSCmdlet.ShouldProcess("access to secret [$Owner/$Name] for repository [$RepositoryID]", 'Remove')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Secrets/SelectedRepository/Set-GitHubSecretSelectedRepository.ps1 b/src/functions/public/Secrets/SelectedRepository/Set-GitHubSecretSelectedRepository.ps1 index b671b8e3a..c82c5c0ce 100644 --- a/src/functions/public/Secrets/SelectedRepository/Set-GitHubSecretSelectedRepository.ps1 +++ b/src/functions/public/Secrets/SelectedRepository/Set-GitHubSecretSelectedRepository.ps1 @@ -56,7 +56,7 @@ $body = @{ selected_repository_ids = @($RepositoryID) } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$Owner/actions/secrets/$Name/repositories" Body = $body @@ -64,7 +64,7 @@ } if ($PSCmdlet.ShouldProcess("access to secret [$Owner/$Name] for repository [$RepositoryID]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Teams/New-GitHubTeam.ps1 b/src/functions/public/Teams/New-GitHubTeam.ps1 index bcaeb2a60..05f4178a1 100644 --- a/src/functions/public/Teams/New-GitHubTeam.ps1 +++ b/src/functions/public/Teams/New-GitHubTeam.ps1 @@ -98,7 +98,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/orgs/$Organization/teams" Body = $body @@ -106,7 +106,7 @@ } if ($PSCmdlet.ShouldProcess("team '$Name' in '$Organization'", 'Create')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($team in $_.Response) { [GitHubTeam]::new($team, $Organization) } diff --git a/src/functions/public/Teams/Remove-GitHubTeam.ps1 b/src/functions/public/Teams/Remove-GitHubTeam.ps1 index 3328a3afc..385043441 100644 --- a/src/functions/public/Teams/Remove-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Remove-GitHubTeam.ps1 @@ -42,14 +42,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Organization/teams/$Slug" Context = $Context } if ($PSCmdlet.ShouldProcess("$Organization/$Slug", 'DELETE')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Teams/Update-GitHubTeam.ps1 b/src/functions/public/Teams/Update-GitHubTeam.ps1 index 1fae8b8a2..642122513 100644 --- a/src/functions/public/Teams/Update-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Update-GitHubTeam.ps1 @@ -95,7 +95,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = "/orgs/$Organization/teams/$Slug" Body = $body @@ -103,7 +103,7 @@ } if ($PSCmdlet.ShouldProcess("$Organization/$Slug", 'Update')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { foreach ($team in $_.Response) { [GitHubTeam]::new($team, $Organization) } diff --git a/src/functions/public/Users/Emails/Add-GitHubUserEmail.ps1 b/src/functions/public/Users/Emails/Add-GitHubUserEmail.ps1 index a2bf8ef70..1ee277e8d 100644 --- a/src/functions/public/Users/Emails/Add-GitHubUserEmail.ps1 +++ b/src/functions/public/Users/Emails/Add-GitHubUserEmail.ps1 @@ -49,14 +49,14 @@ emails = $Email } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/user/emails' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/Emails/Remove-GitHubUserEmail.ps1 b/src/functions/public/Users/Emails/Remove-GitHubUserEmail.ps1 index cbd9f8a3f..2a7ed95ec 100644 --- a/src/functions/public/Users/Emails/Remove-GitHubUserEmail.ps1 +++ b/src/functions/public/Users/Emails/Remove-GitHubUserEmail.ps1 @@ -47,7 +47,7 @@ emails = $Email } - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = '/user/emails' Body = $body @@ -55,7 +55,7 @@ } if ($PSCmdlet.ShouldProcess("Email addresses [$($Email -join ', ')]", 'DELETE')) { - $null = Invoke-GitHubAPI @inputObject | ForEach-Object { + $null = Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/Emails/Update-GitHubUserEmailVisibility.ps1 b/src/functions/public/Users/Emails/Update-GitHubUserEmailVisibility.ps1 index 69581f1ac..67ee2bb42 100644 --- a/src/functions/public/Users/Emails/Update-GitHubUserEmailVisibility.ps1 +++ b/src/functions/public/Users/Emails/Update-GitHubUserEmailVisibility.ps1 @@ -53,7 +53,7 @@ visibility = $Visibility.ToLower() } - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = '/user/email/visibility' Body = $body @@ -61,7 +61,7 @@ } if ($PSCmdlet.ShouldProcess("Email visibility [$Visibility]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject | ForEach-Object { + $null = Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/Followers/Add-GitHubUserFollowing.ps1 b/src/functions/public/Users/Followers/Add-GitHubUserFollowing.ps1 index cbc73efc1..b0f73ecb3 100644 --- a/src/functions/public/Users/Followers/Add-GitHubUserFollowing.ps1 +++ b/src/functions/public/Users/Followers/Add-GitHubUserFollowing.ps1 @@ -45,13 +45,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/user/following/$Username" Context = $Context } - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/public/Users/Followers/Remove-GitHubUserFollowing.ps1 b/src/functions/public/Users/Followers/Remove-GitHubUserFollowing.ps1 index 70b0172a5..2b55d921c 100644 --- a/src/functions/public/Users/Followers/Remove-GitHubUserFollowing.ps1 +++ b/src/functions/public/Users/Followers/Remove-GitHubUserFollowing.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/user/following/$Username" Context = $Context } if ($PSCmdlet.ShouldProcess("User [$Username]", 'Unfollow')) { - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Users/GPG-Keys/Add-GitHubUserGpgKey.ps1 b/src/functions/public/Users/GPG-Keys/Add-GitHubUserGpgKey.ps1 index 0fe941753..3fcfc38df 100644 --- a/src/functions/public/Users/GPG-Keys/Add-GitHubUserGpgKey.ps1 +++ b/src/functions/public/Users/GPG-Keys/Add-GitHubUserGpgKey.ps1 @@ -63,14 +63,14 @@ armored_public_key = $ArmoredPublicKey } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/user/gpg_keys' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 b/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 index 9ca2538f2..72063d617 100644 --- a/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 +++ b/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/user/gpg_keys/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess("GPG key with ID [$ID]", 'DELETE')) { - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Users/Keys/Add-GitHubUserKey.ps1 b/src/functions/public/Users/Keys/Add-GitHubUserKey.ps1 index ffa72bdec..e16740d1d 100644 --- a/src/functions/public/Users/Keys/Add-GitHubUserKey.ps1 +++ b/src/functions/public/Users/Keys/Add-GitHubUserKey.ps1 @@ -57,14 +57,14 @@ key = $Key } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/user/keys' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 b/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 index 91627fb5e..df0688c96 100644 --- a/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 +++ b/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 @@ -44,14 +44,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/user/keys/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess("Key with ID [$ID]", 'DELETE')) { - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Users/SSH-Signing-Keys/Add-GitHubUserSigningKey.ps1 b/src/functions/public/Users/SSH-Signing-Keys/Add-GitHubUserSigningKey.ps1 index d682a4c8d..648782a91 100644 --- a/src/functions/public/Users/SSH-Signing-Keys/Add-GitHubUserSigningKey.ps1 +++ b/src/functions/public/Users/SSH-Signing-Keys/Add-GitHubUserSigningKey.ps1 @@ -59,14 +59,14 @@ key = $Key } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/user/ssh_signing_keys' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 b/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 index f85eceee0..cd41f7a2f 100644 --- a/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 +++ b/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 @@ -45,14 +45,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/user/ssh_signing_keys/$ID" Context = $Context } if ($PSCmdlet.ShouldProcess("SSH signing key with ID [$ID]", 'DELETE')) { - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Users/Social-Accounts/Add-GitHubUserSocial.ps1 b/src/functions/public/Users/Social-Accounts/Add-GitHubUserSocial.ps1 index f31a51f96..3dda88403 100644 --- a/src/functions/public/Users/Social-Accounts/Add-GitHubUserSocial.ps1 +++ b/src/functions/public/Users/Social-Accounts/Add-GitHubUserSocial.ps1 @@ -45,14 +45,14 @@ account_urls = $URL } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = '/user/social_accounts' Body = $body Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Users/Social-Accounts/Remove-GitHubUserSocial.ps1 b/src/functions/public/Users/Social-Accounts/Remove-GitHubUserSocial.ps1 index 27cbb1dba..eaaa15fa6 100644 --- a/src/functions/public/Users/Social-Accounts/Remove-GitHubUserSocial.ps1 +++ b/src/functions/public/Users/Social-Accounts/Remove-GitHubUserSocial.ps1 @@ -46,7 +46,7 @@ account_urls = $URL } - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = '/user/social_accounts' Body = $body @@ -54,7 +54,7 @@ } if ($PSCmdlet.ShouldProcess("Social accounts [$($URL -join ', ')]", 'DELETE')) { - Invoke-GitHubAPI @inputObject + Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Users/Update-GitHubUser.ps1 b/src/functions/public/Users/Update-GitHubUser.ps1 index 7338bb66c..4f97098ec 100644 --- a/src/functions/public/Users/Update-GitHubUser.ps1 +++ b/src/functions/public/Users/Update-GitHubUser.ps1 @@ -92,7 +92,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = '/user' Body = $body @@ -100,7 +100,7 @@ } if ($PSCmdlet.ShouldProcess('authenticated user', 'Set')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubUser]::New($_.Response) } } diff --git a/src/functions/public/Variables/SelectedRepository/Add-GitHubVariableSelectedRepository.ps1 b/src/functions/public/Variables/SelectedRepository/Add-GitHubVariableSelectedRepository.ps1 index 571a10723..37ce7cfcf 100644 --- a/src/functions/public/Variables/SelectedRepository/Add-GitHubVariableSelectedRepository.ps1 +++ b/src/functions/public/Variables/SelectedRepository/Add-GitHubVariableSelectedRepository.ps1 @@ -67,13 +67,13 @@ Write-Debug 'Repo is already selected, returning' return } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$Owner/actions/variables/$Name/repositories/$RepositoryID" Context = $Context } - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } end { diff --git a/src/functions/public/Variables/SelectedRepository/Get-GitHubVariableSelectedRepository.ps1 b/src/functions/public/Variables/SelectedRepository/Get-GitHubVariableSelectedRepository.ps1 index 9effd40da..6947ef247 100644 --- a/src/functions/public/Variables/SelectedRepository/Get-GitHubVariableSelectedRepository.ps1 +++ b/src/functions/public/Variables/SelectedRepository/Get-GitHubVariableSelectedRepository.ps1 @@ -56,13 +56,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/orgs/$Owner/actions/variables/$Name/repositories" Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.repositories | ForEach-Object { [GitHubRepository]::New($_) } diff --git a/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 b/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 index fa5279597..b45fcd0f9 100644 --- a/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 +++ b/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 @@ -75,14 +75,14 @@ Write-Debug 'Repo is not selected, returning' return } - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "/orgs/$Owner/actions/variables/$Name/repositories/$RepositoryID" Context = $Context } if ($PSCmdlet.ShouldProcess("access to variable [$Owner/$Name] for repository [$RepositoryID]", 'Remove')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Variables/SelectedRepository/Set-GitHubVariableSelectedRepository.ps1 b/src/functions/public/Variables/SelectedRepository/Set-GitHubVariableSelectedRepository.ps1 index 45a5b11ca..24e99861b 100644 --- a/src/functions/public/Variables/SelectedRepository/Set-GitHubVariableSelectedRepository.ps1 +++ b/src/functions/public/Variables/SelectedRepository/Set-GitHubVariableSelectedRepository.ps1 @@ -56,7 +56,7 @@ $body = @{ selected_repository_ids = @($RepositoryID) } - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/orgs/$Owner/actions/variables/$Name/repositories" Body = $body @@ -64,7 +64,7 @@ } if ($PSCmdlet.ShouldProcess("access to variable [$Owner/$Name] for repository [$RepositoryID]", 'Set')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Webhooks/Get-GitHubAppWebhookConfiguration.ps1 b/src/functions/public/Webhooks/Get-GitHubAppWebhookConfiguration.ps1 index 15edc15c7..cfaa54435 100644 --- a/src/functions/public/Webhooks/Get-GitHubAppWebhookConfiguration.ps1 +++ b/src/functions/public/Webhooks/Get-GitHubAppWebhookConfiguration.ps1 @@ -37,13 +37,13 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = '/app/hook/config' Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { [GitHubWebhookConfiguration]::new($_.Response) } } diff --git a/src/functions/public/Webhooks/Invoke-GitHubAppWebhookReDelivery.ps1 b/src/functions/public/Webhooks/Invoke-GitHubAppWebhookReDelivery.ps1 index c0ae367e7..c1a649b3a 100644 --- a/src/functions/public/Webhooks/Invoke-GitHubAppWebhookReDelivery.ps1 +++ b/src/functions/public/Webhooks/Invoke-GitHubAppWebhookReDelivery.ps1 @@ -49,14 +49,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/app/hook/deliveries/$ID/attempts" Context = $Context } if ($PSCmdlet.ShouldProcess("[$ID]", 'Redeliver event')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Webhooks/Update-GitHubAppWebhookConfiguration.ps1 b/src/functions/public/Webhooks/Update-GitHubAppWebhookConfiguration.ps1 index 27677c631..1560ada7c 100644 --- a/src/functions/public/Webhooks/Update-GitHubAppWebhookConfiguration.ps1 +++ b/src/functions/public/Webhooks/Update-GitHubAppWebhookConfiguration.ps1 @@ -79,7 +79,7 @@ } $body | Remove-HashtableEntry -NullOrEmptyValues - $inputObject = @{ + $apiParams = @{ Method = 'PATCH' APIEndpoint = '/app/hook/config' Body = $body @@ -87,7 +87,7 @@ } if ($PSCmdlet.ShouldProcess('webhook configuration', 'Update')) { - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response } } diff --git a/src/functions/public/Workflows/Disable-GitHubWorkflow.ps1 b/src/functions/public/Workflows/Disable-GitHubWorkflow.ps1 index d17d2d9dc..8e7cf2661 100644 --- a/src/functions/public/Workflows/Disable-GitHubWorkflow.ps1 +++ b/src/functions/public/Workflows/Disable-GitHubWorkflow.ps1 @@ -46,14 +46,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Repository/actions/workflows/$ID/disable" Context = $Context } if ($PSCmdlet.ShouldProcess("$Owner/$Repository/$ID", 'Disable workflow')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Workflows/Enable-GitHubWorkflow.ps1 b/src/functions/public/Workflows/Enable-GitHubWorkflow.ps1 index b93f601da..49d9b4c41 100644 --- a/src/functions/public/Workflows/Enable-GitHubWorkflow.ps1 +++ b/src/functions/public/Workflows/Enable-GitHubWorkflow.ps1 @@ -43,14 +43,14 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'PUT' APIEndpoint = "/repos/$Owner/$Repository/actions/workflows/$ID/enable" Context = $Context } if ($PSCmdlet.ShouldProcess("$Owner/$Repository/$ID", 'Enable workflow')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Workflows/Get-GitHubWorkflow.ps1 b/src/functions/public/Workflows/Get-GitHubWorkflow.ps1 index 866a6c958..d9a4ba822 100644 --- a/src/functions/public/Workflows/Get-GitHubWorkflow.ps1 +++ b/src/functions/public/Workflows/Get-GitHubWorkflow.ps1 @@ -61,7 +61,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'GET' APIEndpoint = "/repos/$Owner/$Repository/actions/workflows" Body = $body @@ -69,7 +69,7 @@ Context = $Context } - Invoke-GitHubAPI @inputObject | ForEach-Object { + Invoke-GitHubAPI @apiParams | ForEach-Object { Write-Output $_.Response.workflows | Where-Object { $_.name -like $Name } | ForEach-Object { [GitHubWorkflow]::new($_, $Owner, $Repository) } diff --git a/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 b/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 index 083e325fc..14cab3e13 100644 --- a/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 +++ b/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 @@ -50,7 +50,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'DELETE' APIEndpoint = "repos/$Owner/$Repository/actions/runs/$ID" Context = $Context @@ -58,7 +58,7 @@ if ($PSCmdlet.ShouldProcess("$Owner/$Repository/$ID", 'Delete workflow run')) { Write-Verbose "Deleted workflow run [$ID] in [$Owner/$Repository]" - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Workflows/Runs/Restart-GitHubWorkflowRun.ps1 b/src/functions/public/Workflows/Runs/Restart-GitHubWorkflowRun.ps1 index c1f0df4f9..4011fca79 100644 --- a/src/functions/public/Workflows/Runs/Restart-GitHubWorkflowRun.ps1 +++ b/src/functions/public/Workflows/Runs/Restart-GitHubWorkflowRun.ps1 @@ -46,7 +46,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/actions/runs/$ID/rerun" Context = $Context @@ -54,7 +54,7 @@ if ($PSCmdlet.ShouldProcess("workflow with ID [$ID] in [$Owner/$Repository]", 'Re-run')) { Write-Verbose "Re-run workflow [$ID] in [$Owner/$Repository]" - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Workflows/Runs/Stop-GitHubWorkflowRun.ps1 b/src/functions/public/Workflows/Runs/Stop-GitHubWorkflowRun.ps1 index ca67a06af..c166b7573 100644 --- a/src/functions/public/Workflows/Runs/Stop-GitHubWorkflowRun.ps1 +++ b/src/functions/public/Workflows/Runs/Stop-GitHubWorkflowRun.ps1 @@ -49,7 +49,7 @@ } process { - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/actions/runs/$ID/cancel" Context = $Context @@ -57,7 +57,7 @@ if ($PSCmdlet.ShouldProcess("$Owner/$Repository/$ID", 'Cancel/Stop workflow run')) { Write-Verbose "Cancelled workflow run [$ID] in [$Owner/$Repository]" - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } diff --git a/src/functions/public/Workflows/Start-GitHubWorkflow.ps1 b/src/functions/public/Workflows/Start-GitHubWorkflow.ps1 index 8d6481ccc..3a651b57e 100644 --- a/src/functions/public/Workflows/Start-GitHubWorkflow.ps1 +++ b/src/functions/public/Workflows/Start-GitHubWorkflow.ps1 @@ -62,7 +62,7 @@ inputs = $Inputs } - $inputObject = @{ + $apiParams = @{ Method = 'POST' APIEndpoint = "/repos/$Owner/$Repository/actions/workflows/$ID/dispatches" Body = $body @@ -70,7 +70,7 @@ } if ($PSCmdlet.ShouldProcess("$Owner/$Repository/$ID", 'Start workflow')) { - $null = Invoke-GitHubAPI @inputObject + $null = Invoke-GitHubAPI @apiParams } } From f2b89e4396be44fad690a3da105b6bf39a415352 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Jul 2025 14:56:19 +0200 Subject: [PATCH 12/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Request=20confi?= =?UTF-8?q?rmation=20before=20removing/deleting=20resources=20where=20reco?= =?UTF-8?q?very=20is=20difficult/impossible=20(#465)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request updates multiple PowerShell functions to enhance user safety by adding a `ConfirmImpact = 'High'` attribute to the `[CmdletBinding]` declaration for commands that perform destructive operations. This ensures users are explicitly prompted before executing high-impact actions. Additionally, some minor formatting adjustments are made. - Fixes #184 ### Adjustments to `ConfirmImpact` values: * Updated high-impact function to prompt for confirmation (`ConfirmImpact = 'High'`). * Removed `ConfirmImpact` attribute for functions that have low impact. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> --- src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 | 4 ++-- .../public/Environments/Remove-GitHubEnvironment.ps1 | 4 ++-- .../public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 | 4 ++-- src/functions/public/Releases/Remove-GitHubRelease.ps1 | 4 ++-- src/functions/public/Secrets/Remove-GitHubSecret.ps1 | 2 +- .../Remove-GitHubSecretSelectedRepository.ps1 | 2 +- src/functions/public/Teams/Remove-GitHubTeam.ps1 | 2 +- .../public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 | 4 ++-- src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 | 4 ++-- .../Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 | 4 ++-- src/functions/public/Variables/Remove-GitHubVariable.ps1 | 2 +- .../Remove-GitHubVariableSelectedRepository.ps1 | 2 +- .../public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 | 4 ++-- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 b/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 index aa11d5811..747d32150 100644 --- a/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 +++ b/src/functions/public/Artifacts/Remove-GitHubArtifact.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubArtifact { +function Remove-GitHubArtifact { <# .SYNOPSIS Deletes an artifact from a GitHub repository by its unique ID. @@ -31,7 +31,7 @@ [Delete an artifact](https://docs.github.com/rest/actions/artifacts#delete-an-artifact) #> [OutputType([GitHubArtifact])] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] diff --git a/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 b/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 index a223d953f..393d988f1 100644 --- a/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 +++ b/src/functions/public/Environments/Remove-GitHubEnvironment.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubEnvironment { +filter Remove-GitHubEnvironment { <# .SYNOPSIS Deletes an environment from a repository. @@ -19,7 +19,7 @@ [Delete environments](https://docs.github.com/rest/deployments/environments?#delete-an-environment) #> [OutputType([void])] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The name of the organization. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] diff --git a/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 index fccd994fd..76efada9c 100644 --- a/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubReleaseAsset { +filter Remove-GitHubReleaseAsset { <# .SYNOPSIS Delete a release asset @@ -20,7 +20,7 @@ .NOTES [Delete a release asset](https://docs.github.com/rest/releases/assets#delete-a-release-asset) #> - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory)] diff --git a/src/functions/public/Releases/Remove-GitHubRelease.ps1 b/src/functions/public/Releases/Remove-GitHubRelease.ps1 index babda52a4..6bddf1cb0 100644 --- a/src/functions/public/Releases/Remove-GitHubRelease.ps1 +++ b/src/functions/public/Releases/Remove-GitHubRelease.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubRelease { +filter Remove-GitHubRelease { <# .SYNOPSIS Delete a release @@ -24,7 +24,7 @@ [Delete a release](https://docs.github.com/rest/releases/releases#delete-a-release) #> [OutputType([void])] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] diff --git a/src/functions/public/Secrets/Remove-GitHubSecret.ps1 b/src/functions/public/Secrets/Remove-GitHubSecret.ps1 index 4c8295d57..2d4f1a4b4 100644 --- a/src/functions/public/Secrets/Remove-GitHubSecret.ps1 +++ b/src/functions/public/Secrets/Remove-GitHubSecret.ps1 @@ -32,7 +32,7 @@ 'PSShouldProcess', '', Scope = 'Function', Justification = 'This check is performed in the private functions.' )] - [CmdletBinding(DefaultParameterSetName = 'AuthenticatedUser', SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName = 'AuthenticatedUser', SupportsShouldProcess, ConfirmImpact = 'High')] param ( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory, ParameterSetName = 'Organization', ValueFromPipelineByPropertyName)] diff --git a/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 b/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 index 4306b7fab..e4c97e672 100644 --- a/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 +++ b/src/functions/public/Secrets/SelectedRepository/Remove-GitHubSecretSelectedRepository.ps1 @@ -28,7 +28,7 @@ Justification = 'Long links' )] [OutputType([void])] - [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] + [CmdletBinding(SupportsShouldProcess)] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory)] diff --git a/src/functions/public/Teams/Remove-GitHubTeam.ps1 b/src/functions/public/Teams/Remove-GitHubTeam.ps1 index 385043441..b795eca9a 100644 --- a/src/functions/public/Teams/Remove-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Remove-GitHubTeam.ps1 @@ -17,7 +17,7 @@ https://psmodule.io/GitHub/Functions/Teams/Remove-GitHubTeam #> [OutputType([void])] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The organization name. The name is not case sensitive. # If not provided, the organization from the context is used. diff --git a/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 b/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 index 72063d617..b577a1fff 100644 --- a/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 +++ b/src/functions/public/Users/GPG-Keys/Remove-GitHubUserGpgKey.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubUserGpgKey { +filter Remove-GitHubUserGpgKey { <# .SYNOPSIS Delete a GPG key for the authenticated user @@ -20,7 +20,7 @@ https://psmodule.io/GitHub/Functions/Users/GPG-Keys/Remove-GitHubUserGpgKey #> [OutputType([pscustomobject])] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The ID of the GPG key. [Parameter( diff --git a/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 b/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 index df0688c96..661cc342d 100644 --- a/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 +++ b/src/functions/public/Users/Keys/Remove-GitHubUserKey.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubUserKey { +filter Remove-GitHubUserKey { <# .SYNOPSIS Delete a public SSH key for the authenticated user @@ -21,7 +21,7 @@ #> [OutputType([pscustomobject])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The unique identifier of the key. [Parameter( diff --git a/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 b/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 index cd41f7a2f..f9fdd5154 100644 --- a/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 +++ b/src/functions/public/Users/SSH-Signing-Keys/Remove-GitHubUserSigningKey.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubUserSigningKey { +filter Remove-GitHubUserSigningKey { <# .SYNOPSIS Delete an SSH signing key for the authenticated user @@ -22,7 +22,7 @@ #> [OutputType([pscustomobject])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The unique identifier of the SSH signing key. [Parameter( diff --git a/src/functions/public/Variables/Remove-GitHubVariable.ps1 b/src/functions/public/Variables/Remove-GitHubVariable.ps1 index caee1d0e7..ffe376cc3 100644 --- a/src/functions/public/Variables/Remove-GitHubVariable.ps1 +++ b/src/functions/public/Variables/Remove-GitHubVariable.ps1 @@ -42,7 +42,7 @@ Justification = 'This check is performed in the private functions.' )] [OutputType([void])] - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory, ParameterSetName = 'Organization', ValueFromPipelineByPropertyName)] diff --git a/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 b/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 index b45fcd0f9..a81a40bac 100644 --- a/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 +++ b/src/functions/public/Variables/SelectedRepository/Remove-GitHubVariableSelectedRepository.ps1 @@ -37,7 +37,7 @@ Justification = 'Long links' )] [OutputType([void])] - [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] + [CmdletBinding(SupportsShouldProcess)] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory)] diff --git a/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 b/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 index 14cab3e13..cd92f4a61 100644 --- a/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 +++ b/src/functions/public/Workflows/Runs/Remove-GitHubWorkflowRun.ps1 @@ -1,4 +1,4 @@ -filter Remove-GitHubWorkflowRun { +filter Remove-GitHubWorkflowRun { <# .SYNOPSIS Delete a workflow run @@ -22,7 +22,7 @@ .NOTES [Delete a workflow run](https://docs.github.com/rest/actions/workflow-runs#delete-a-workflow-run) #> - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( # The account owner of the repository. The name is not case sensitive. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] From 26ca2a509bc5a58a4248ec990dfd0cda0be386c3 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 10 Jul 2025 18:30:23 +0200 Subject: [PATCH 13/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Update=20Assert?= =?UTF-8?q?-GitHubContext=20error=20message=20to=20include=20context=20typ?= =?UTF-8?q?e=20info=20(#469)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces improvements to error handling and messaging in PowerShell scripts related to GitHub context validation and GraphQL query execution. The changes enhance clarity and provide more detailed error information for debugging purposes. - Fixes #468 ### Improvements to error handling * Enhanced error message formatting in `Assert-GitHubContext.ps1`: Updated the error message to include the context name, type, and required types in a more readable format. This improves clarity when the context authentication type does not match the required types for a command. * Detailed GraphQL error messages in `Invoke-GitHubGraphQLQuery.ps1`: Added a clear header ("GraphQL errors occurred") and moved the full error details to the beginning of the error message. This change makes the error output more structured and easier to interpret. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug --- .../private/Auth/Context/Assert-GitHubContext.ps1 | 5 ++++- src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/functions/private/Auth/Context/Assert-GitHubContext.ps1 b/src/functions/private/Auth/Context/Assert-GitHubContext.ps1 index 525037a89..60538b622 100644 --- a/src/functions/private/Auth/Context/Assert-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Assert-GitHubContext.ps1 @@ -53,9 +53,12 @@ } if ($Context -eq 'Anonymous' -and $AuthType -contains 'Anonymous') { return } if ($Context.AuthType -in $AuthType) { return } + + $errorText = "The context '$($Context.Name)' is of type [$($Context.AuthType)] which does not match the required" + + "types [$($AuthType -join ', ')] for [$command]." $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( - [System.Exception]::new("The context '$($Context.Name)' does not match the required AuthTypes [$AuthType] for [$command]."), + [System.Exception]::new($errorText), 'InvalidContextAuthType', [System.Management.Automation.ErrorCategory]::InvalidArgument, $Context diff --git a/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 b/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 index 4c62a1ac5..6da9cd426 100644 --- a/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 +++ b/src/functions/public/API/Invoke-GitHubGraphQLQuery.ps1 @@ -60,21 +60,23 @@ $queryLines = $Query -split "`n" | ForEach-Object { $_.Trim() } foreach ($errorItem in $graphQLResponse.errors) { $errorMessages += @" + +GraphQL errors occurred: +Full Error: +$($errorItem | ConvertTo-Json -Depth 10 | Out-String) + GraphQL Error [$($errorItem.type)]: Message: $($errorItem.message) Path: $($errorItem.path -join '/') Locations: $($errorItem.locations | ForEach-Object { " - [$($_.line):$($_.column)] - $($queryLines[$_.line - 1])" }) -Full Error: -$($errorItem | ConvertTo-Json -Depth 10 | Out-String -Stream) - "@ } $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( - [System.Exception]::new("GraphQL errors occurred:`n$($errorMessages -join "`n`n")"), + [System.Exception]::new($errorMessages), 'GraphQLError', [System.Management.Automation.ErrorCategory]::InvalidOperation, $graphQLResponse From 6d8471ba638a40674471dcff5da0615ffd140fe4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:05:05 +0200 Subject: [PATCH 14/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Standardize=20D?= =?UTF-8?q?ateTime=20and=20TimeSpan=20property=20naming=20convention=20(#4?= =?UTF-8?q?67)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces several changes to improve code clarity, consistency, and functionality across multiple files. The most significant updates involve renaming properties for better readability, adding new functionality for handling expiration times, and modifying constructors and formatting files to align with these changes. ### Property Renaming for Consistency * Renamed `TokenExpirationDate` to `TokenExpiresAt` in `[InstallationGitHubContext]` and `[UserGitHubContext]`. Updated all related assignments and references accordingly. * Renamed `RefreshTokenExpirationDate` to `RefreshTokenExpiresAt` in `[UserGitHubContext]`. Updated references in constructors and methods. * Renamed `Reset` to `ResetsAt` in `GithubRateLimitResource` and updated its constructor to calculate `ResetsAt` using Unix epoch time. ### Handling Expiration Times * Added a `ExpiresIn` script property to the `[GitHubArtifact]` type to calculate remaining time until expiration dynamically. * Updated logic in `Test-GitHubAccessTokenRefreshRequired` and `Update-GitHubUserAccessToken` to use `TokenExpiresAt` and `RefreshTokenExpiresAt` for expiration checks. ### Formatting and Output Enhancements * Updated formats for `[GitHubContext]` and `[GitHubRateLimitResource]` to reflect renamed properties (`TokenExpiresAt`, `ResetsAt`) and added new labels (`TokenExpiresIn`, `ResetsIn`). * Improved list formatting in `Get-GitHubRateLimit` for better readability and updated the output type to `GitHubRateLimitResource`. [[1]](diffhunk://#diff-fb1d1f2f0c6408f7e57b571e58424a515ce78bf35281ef778d2924a674dce150L11-R19) [[2]](diffhunk://#diff-fb1d1f2f0c6408f7e57b571e58424a515ce78bf35281ef778d2924a674dce150R29-R31) ### Constructor Updates: * Simplified constructors in `GithubRateLimitResource.ps1` by removing the hashtable-based initialization and using `PSCustomObject` directly. * Updated constructors in `Connect-GitHubAccount.ps1` and `Connect-GitHubApp.ps1` to use the new property names and expiration handling. [[1]](diffhunk://#diff-12918e90451cdedb78571b9a67ac0313331a25175cebb606b7108b7bf06af092L222-R227) [[2]](diffhunk://#diff-7d1951ca779d73ee11b11db4ade6f33f8ea5fcf052324a72d2c8e83304eaa045L142-R142) ### Build and Test Configuration: * Added `Skip` directives for various test and build steps in `.github/PSModule.yml` to streamline CI/CD workflows. --------- Co-authored-by: Marius Storhaug --- .github/PSModule.yml | 21 ++++++++ .../InstallationGitHubContext.ps1 | 4 +- .../GitHubContext/UserGitHubContext.ps1 | 8 ++-- .../RateLimit/GithubRateLimitResource.ps1 | 19 +++----- src/formats/GitHubContext.Format.ps1xml | 24 +++++++--- .../GitHubRateLimitResource.Format.ps1xml | 10 +++- .../Test-GitHubAccessTokenRefreshRequired.ps1 | 4 +- .../Update-GitHubUserAccessToken.ps1 | 6 +-- ...et-GitHubAppWebhookDeliveryToRedeliver.ps1 | 2 +- .../public/Auth/Connect-GitHubAccount.ps1 | 16 +++---- .../public/Auth/Connect-GitHubApp.ps1 | 30 ++++++------ .../public/Rate-Limit/Get-GitHubRateLimit.ps1 | 39 +++++++-------- src/types/GitHubArtifact.Types.ps1xml | 19 ++++++++ src/types/GitHubContext.Types.ps1xml | 31 +++++++++--- src/types/GitHubJsonWebToken.Types.ps1xml | 19 ++++++++ .../GitHubRateLimitResource.Types.ps1xml | 19 ++++++++ tests/Apps.Tests.ps1 | 8 +++- tests/GitHub.Tests.ps1 | 48 +++++++++++++++++-- 18 files changed, 236 insertions(+), 91 deletions(-) create mode 100644 src/types/GitHubArtifact.Types.ps1xml create mode 100644 src/types/GitHubJsonWebToken.Types.ps1xml create mode 100644 src/types/GitHubRateLimitResource.Types.ps1xml diff --git a/.github/PSModule.yml b/.github/PSModule.yml index 6d578178e..d14ee6fa2 100644 --- a/.github/PSModule.yml +++ b/.github/PSModule.yml @@ -1,3 +1,24 @@ Test: + SourceCode: + Windows: + Skip: true + MacOS: + Skip: true + PSModule: + Windows: + Skip: true + MacOS: + Skip: true + Module: + Windows: + Skip: true + MacOS: + Skip: true + TestResults: + Skip: true CodeCoverage: + Skip: true PercentTarget: 50 +Build: + Docs: + Skip: true diff --git a/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 index c1a6ec77a..2f0ae9764 100644 --- a/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 @@ -4,7 +4,7 @@ # The token expiration date. # 2024-01-01-00:00:00 - [System.Nullable[datetime]] $TokenExpirationDate + [System.Nullable[datetime]] $TokenExpiresAt # The installation ID. [System.Nullable[uint64]] $InstallationID @@ -43,7 +43,7 @@ $this.HttpVersion = $Object.HttpVersion $this.PerPage = $Object.PerPage $this.ClientID = $Object.ClientID - $this.TokenExpirationDate = $Object.TokenExpirationDate + $this.TokenExpiresAt = $Object.TokenExpiresAt $this.InstallationID = $Object.InstallationID $this.Permissions = $Object.Permissions $this.Events = $Object.Events diff --git a/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 index fad314e37..0a769b13f 100644 --- a/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 @@ -13,14 +13,14 @@ # The token expiration date. # 2024-01-01-00:00:00 - [System.Nullable[datetime]] $TokenExpirationDate + [System.Nullable[datetime]] $TokenExpiresAt # The refresh token. [securestring] $RefreshToken # The refresh token expiration date. # 2024-01-01-00:00:00 - [System.Nullable[datetime]] $RefreshTokenExpirationDate + [System.Nullable[datetime]] $RefreshTokenExpiresAt UserGitHubContext() {} @@ -46,8 +46,8 @@ $this.AuthClientID = $Object.AuthClientID $this.DeviceFlowType = $Object.DeviceFlowType $this.Scope = $Object.Scope - $this.TokenExpirationDate = $Object.TokenExpirationDate + $this.TokenExpiresAt = $Object.TokenExpiresAt $this.RefreshToken = $Object.RefreshToken - $this.RefreshTokenExpirationDate = $Object.RefreshTokenExpirationDate + $this.RefreshTokenExpiresAt = $Object.RefreshTokenExpiresAt } } diff --git a/src/classes/public/RateLimit/GithubRateLimitResource.ps1 b/src/classes/public/RateLimit/GithubRateLimitResource.ps1 index 00ae7a91f..b53bbdceb 100644 --- a/src/classes/public/RateLimit/GithubRateLimitResource.ps1 +++ b/src/classes/public/RateLimit/GithubRateLimitResource.ps1 @@ -12,22 +12,17 @@ [UInt64] $Remaining # The time when the rate limit will reset. - [DateTime] $Reset + [DateTime] $ResetsAt # Simple parameterless constructor GitHubRateLimitResource() {} - # Constructor that initializes the class from a hashtable - GitHubRateLimitResource([hashtable]$Properties) { - foreach ($Property in $Properties.Keys) { - $this.$Property = $Properties.$Property - } - } - # Constructor that initializes the class from a PSCustomObject - GitHubRateLimitResource([PSCustomObject]$Object) { - $Object.PSObject.Properties | ForEach-Object { - $this.($_.Name) = $_.Value - } + GitHubRateLimitResource([pscustomobject]$Object) { + $this.Name = $Object.name + $this.Limit = $Object.limit + $this.Used = $Object.used + $this.Remaining = $Object.remaining + $this.ResetsAt = [DateTime]::UnixEpoch.AddSeconds($Object.reset).ToLocalTime() } } diff --git a/src/formats/GitHubContext.Format.ps1xml b/src/formats/GitHubContext.Format.ps1xml index 28a1a0b11..363dfceed 100644 --- a/src/formats/GitHubContext.Format.ps1xml +++ b/src/formats/GitHubContext.Format.ps1xml @@ -24,10 +24,10 @@ - + - + @@ -50,7 +50,7 @@ TokenType - TokenExpirationDate + TokenExpiresAt @@ -61,7 +61,8 @@ if ($_.Remaining -lt 0) { $text = "Expired" } else { - $text = "$($_.Remaining.Hours)h $($_.Remaining.Minutes)m $($_.Remaining.Seconds)s" + $text = "$($_.Remaining.Hours)h $($_.Remaining.Minutes)m + $($_.Remaining.Seconds)s" } if ($Host.UI.SupportsVirtualTerminal -and @@ -266,7 +267,10 @@ InstallationID - TokenExpirationDate + TokenExpiresAt + + + TokenExpiresIn InstallationType @@ -340,10 +344,16 @@ Scope - TokenExpirationDate + TokenExpiresAt + + + TokenExpiresIn + + + RefreshTokenExpiresAt - RefreshTokenExpirationDate + RefreshTokenExpiresIn ApiBaseUri diff --git a/src/formats/GitHubRateLimitResource.Format.ps1xml b/src/formats/GitHubRateLimitResource.Format.ps1xml index 0e4c7c898..b9e4bdc9d 100644 --- a/src/formats/GitHubRateLimitResource.Format.ps1xml +++ b/src/formats/GitHubRateLimitResource.Format.ps1xml @@ -21,7 +21,10 @@ - + + + + @@ -40,7 +43,10 @@ Remaining - Reset + ResetsAt + + + ResetsIn diff --git a/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 b/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 index 0692c09df..d9320a85d 100644 --- a/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 @@ -26,9 +26,7 @@ } process { - $tokenExpirationDate = $Context.TokenExpirationDate - $remainingDuration = [datetime]$tokenExpirationDate - [datetime]::Now - $updateToken = $remainingDuration.TotalHours -lt $script:GitHub.Config.AccessTokenGracePeriodInHours + $updateToken = ($Context.TokenExpiresAt - [datetime]::Now).TotalHours -lt $script:GitHub.Config.AccessTokenGracePeriodInHours $updateToken } diff --git a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 index b67263f90..6fba80ca1 100644 --- a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 @@ -59,7 +59,7 @@ if ($updateToken) { try { - $refreshTokenValidity = [datetime]($Context.RefreshTokenExpirationDate) - [datetime]::Now + $refreshTokenValidity = [datetime]($Context.RefreshTokenExpiresAt) - [datetime]::Now $refreshTokenIsValid = $refreshTokenValidity.TotalSeconds -gt 0 if ($refreshTokenIsValid) { if (-not $Silent) { @@ -72,10 +72,10 @@ $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $Context.AuthClientID -HostName $Context.HostName } $Context.Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token - $Context.TokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.expires_in) + $Context.TokenExpiresAt = ([DateTime]::Now).AddSeconds($tokenResponse.expires_in) $Context.TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern $Context.RefreshToken = ConvertTo-SecureString -AsPlainText $tokenResponse.refresh_token - $Context.RefreshTokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.refresh_token_expires_in) + $Context.RefreshTokenExpiresAt = ([DateTime]::Now).AddSeconds($tokenResponse.refresh_token_expires_in) if ($PSCmdlet.ShouldProcess('Access token', 'Update/refresh')) { Set-Context -Context $Context -Vault $script:GitHub.ContextVault diff --git a/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryToRedeliver.ps1 b/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryToRedeliver.ps1 index 923c6f9d3..957dad479 100644 --- a/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryToRedeliver.ps1 +++ b/src/functions/private/Webhooks/Get-GitHubAppWebhookDeliveryToRedeliver.ps1 @@ -34,7 +34,7 @@ } process { - $checkPoint = (Get-Date).AddHours($TimeSpan) + $checkPoint = ([DateTime]::Now).AddHours($TimeSpan) Get-GitHubAppWebhookDeliveryByList -Context $Context -PerPage $PerPage | Where-Object { $_.DeliveredAt -gt $checkPoint } | Group-Object -Property GUID | Where-Object { $_.Group.Status -notcontains 'OK' } | ForEach-Object { $refObject = $_.Group | Sort-Object -Property DeliveredAt diff --git a/src/functions/public/Auth/Connect-GitHubAccount.ps1 b/src/functions/public/Auth/Connect-GitHubAccount.ps1 index 0cbd037ec..b2abd70af 100644 --- a/src/functions/public/Auth/Connect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Connect-GitHubAccount.ps1 @@ -218,14 +218,14 @@ switch ($Mode) { 'GitHubApp' { $context += @{ - Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token - TokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.expires_in) - TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern - AuthClientID = $authClientID - DeviceFlowType = $Mode - RefreshToken = ConvertTo-SecureString -AsPlainText $tokenResponse.refresh_token - RefreshTokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.refresh_token_expires_in) - Scope = $tokenResponse.scope + Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token + TokenExpiresAt = ([DateTime]::Now).AddSeconds($tokenResponse.expires_in) + TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern + AuthClientID = $authClientID + DeviceFlowType = $Mode + RefreshToken = ConvertTo-SecureString -AsPlainText $tokenResponse.refresh_token + RefreshTokenExpiresAt = ([DateTime]::Now).AddSeconds($tokenResponse.refresh_token_expires_in) + Scope = $tokenResponse.scope } } 'OAuthApp' { diff --git a/src/functions/public/Auth/Connect-GitHubApp.ps1 b/src/functions/public/Auth/Connect-GitHubApp.ps1 index 1994c5082..0bb9a8012 100644 --- a/src/functions/public/Auth/Connect-GitHubApp.ps1 +++ b/src/functions/public/Auth/Connect-GitHubApp.ps1 @@ -125,21 +125,21 @@ $token = New-GitHubAppInstallationAccessToken -Context $Context -ID $installation.id $contextParams = @{ - AuthType = [string]'IAT' - TokenType = [string]'ghs' - DisplayName = [string]$Context.DisplayName - ApiBaseUri = [string]$Context.ApiBaseUri - ApiVersion = [string]$Context.ApiVersion - HostName = [string]$Context.HostName - HttpVersion = [string]$Context.HttpVersion - PerPage = [int]$Context.PerPage - ClientID = [string]$Context.ClientID - InstallationID = [string]$installation.id - Permissions = [pscustomobject]$installation.permissions - Events = [string[]]$installation.events - InstallationType = [string]$installation.Type - Token = [securestring]$token.Token - TokenExpirationDate = [datetime]$token.ExpiresAt + AuthType = [string]'IAT' + TokenType = [string]'ghs' + DisplayName = [string]$Context.DisplayName + ApiBaseUri = [string]$Context.ApiBaseUri + ApiVersion = [string]$Context.ApiVersion + HostName = [string]$Context.HostName + HttpVersion = [string]$Context.HttpVersion + PerPage = [int]$Context.PerPage + ClientID = [string]$Context.ClientID + InstallationID = [string]$installation.id + Permissions = [pscustomobject]$installation.permissions + Events = [string[]]$installation.events + InstallationType = [string]$installation.Type + Token = [securestring]$token.Token + TokenExpiresAt = [datetime]$token.ExpiresAt } switch ($installation.Type) { diff --git a/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 b/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 index 8183619cd..c7a6830c0 100644 --- a/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 +++ b/src/functions/public/Rate-Limit/Get-GitHubRateLimit.ps1 @@ -8,15 +8,15 @@ Some categories of endpoints have custom rate limits that are separate from the rate limit governing the other REST API endpoints. For this reason, the API response categorizes your rate limit. Under `resources`, you'll see objects relating to different categories: - * The `core` object provides your rate limit status for all non-search-related resources in the REST API. - * The `search` object provides your rate limit status for the REST API for searching (excluding code searches). For more information, see "[Search](https://docs.github.com/rest/search)." - * The `code_search` object provides your rate limit status for the REST API for searching code. For more information, see "[Search code](https://docs.github.com/rest/search/search#search-code)." - * The `graphql` object provides your rate limit status for the GraphQL API. For more information, see "[Resource limitations](https://docs.github.com/graphql/overview/resource-limitations#rate-limit)." - * The `integration_manifest` object provides your rate limit status for the `POST /app-manifests/{code}/conversions` operation. For more information, see "[Creating a GitHub App from a manifest](https://docs.github.com/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app-from-a-manifest#3-you-exchange-the-temporary-code-to-retrieve-the-app-configuration)." - * The `dependency_snapshots` object provides your rate limit status for submitting snapshots to the dependency graph. For more information, see "[Dependency graph](https://docs.github.com/rest/dependency-graph)." - * The `code_scanning_upload` object provides your rate limit status for uploading SARIF results to code scanning. For more information, see "[Uploading a SARIF file to GitHub](https://docs.github.com/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github)." - * The `actions_runner_registration` object provides your rate limit status for registering self-hosted runners in GitHub Actions. For more information, see "[Self-hosted runners](https://docs.github.com/rest/actions/self-hosted-runners)." - * The `source_import` object is no longer in use for any API endpoints, and it will be removed in the next API version. For more information about API versions, see "[API Versions](https://docs.github.com/rest/overview/api-versions)." + - The `core` object provides your rate limit status for all non-search-related resources in the REST API. + - The `search` object provides your rate limit status for the REST API for searching (excluding code searches). For more information, see "[Search](https://docs.github.com/rest/search)." + - The `code_search` object provides your rate limit status for the REST API for searching code. For more information, see "[Search code](https://docs.github.com/rest/search/search#search-code)." + - The `graphql` object provides your rate limit status for the GraphQL API. For more information, see "[Resource limitations](https://docs.github.com/graphql/overview/resource-limitations#rate-limit)." + - The `integration_manifest` object provides your rate limit status for the `POST /app-manifests/{code}/conversions` operation. For more information, see "[Creating a GitHub App from a manifest](https://docs.github.com/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app-from-a-manifest#3-you-exchange-the-temporary-code-to-retrieve-the-app-configuration)." + - The `dependency_snapshots` object provides your rate limit status for submitting snapshots to the dependency graph. For more information, see "[Dependency graph](https://docs.github.com/rest/dependency-graph)." + - The `code_scanning_upload` object provides your rate limit status for uploading SARIF results to code scanning. For more information, see "[Uploading a SARIF file to GitHub](https://docs.github.com/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github)." + - The `actions_runner_registration` object provides your rate limit status for registering self-hosted runners in GitHub Actions. For more information, see "[Self-hosted runners](https://docs.github.com/rest/actions/self-hosted-runners)." + - The `source_import` object is no longer in use for any API endpoints, and it will be removed in the next API version. For more information about API versions, see "[API Versions](https://docs.github.com/rest/overview/api-versions)." **Note:** The `rate` object is deprecated. If you're writing new API client code or updating existing code, you should use the `core` object instead of the `rate` object. The `core` object contains the same information that is present in the `rate` object. @@ -26,6 +26,9 @@ Gets the rate limit status for the authenticated user. + .OUTPUTS + GitHubRateLimitResource + .NOTES [Get rate limit status for the authenticated user](https://docs.github.com/rest/rate-limit/rate-limit#get-rate-limit-status-for-the-authenticated-user) @@ -62,22 +65,12 @@ Invoke-GitHubAPI @apiParams | ForEach-Object { $_.Response.Resources.PSObject.Properties | ForEach-Object { - [GitHubRateLimitResource]@{ - Name = $_.Name - Limit = $_.Value.limit - Used = $_.Value.used - Remaining = $_.Value.remaining - Reset = [DateTime]::UnixEpoch.AddSeconds($_.Value.reset).ToLocalTime() - } + $resource = $_.Value | Add-Member -MemberType NoteProperty -Name 'name' -Value $_.Name -PassThru + [GitHubRateLimitResource]::new($resource) } if ($_.Response.Rate) { - [GitHubRateLimitResource]@{ - Name = 'rate' - Limit = $_.Response.Rate.limit - Used = $_.Response.Rate.used - Remaining = $_.Response.Rate.remaining - Reset = [DateTime]::UnixEpoch.AddSeconds($_.Response.Rate.reset).ToLocalTime() - } + $resource = $_.Response.Rate | Add-Member -MemberType NoteProperty -Name 'name' -Value 'rate' -PassThru + [GitHubRateLimitResource]::new($resource) } } } diff --git a/src/types/GitHubArtifact.Types.ps1xml b/src/types/GitHubArtifact.Types.ps1xml new file mode 100644 index 000000000..39c87f736 --- /dev/null +++ b/src/types/GitHubArtifact.Types.ps1xml @@ -0,0 +1,19 @@ + + + + GitHubArtifact + + + ExpiresIn + + if ($null -eq $this.ExpiresAt) { return } + $timeRemaining = $this.ExpiresAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining + + + + + diff --git a/src/types/GitHubContext.Types.ps1xml b/src/types/GitHubContext.Types.ps1xml index f76b0b424..0fde8366a 100644 --- a/src/types/GitHubContext.Types.ps1xml +++ b/src/types/GitHubContext.Types.ps1xml @@ -4,10 +4,25 @@ UserGitHubContext - Remaining + TokenExpiresIn - if ($null -eq $this.TokenExpirationDate) { return } - New-TimeSpan -Start ([datetime]::Now) -End $this.TokenExpirationDate + if ($null -eq $this.TokenExpiresAt) { return } + $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining + + + + RefreshTokenExpiresIn + + if ($null -eq $this.RefreshTokenExpiresAt) { return } + $timeRemaining = $this.RefreshTokenExpiresAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining @@ -16,10 +31,14 @@ InstallationGitHubContext - Remaining + TokenExpiresIn - if ($null -eq $this.TokenExpirationDate) { return } - New-TimeSpan -Start ([datetime]::Now) -End $this.TokenExpirationDate + if ($null -eq $this.TokenExpiresAt) { return } + $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining diff --git a/src/types/GitHubJsonWebToken.Types.ps1xml b/src/types/GitHubJsonWebToken.Types.ps1xml new file mode 100644 index 000000000..da5897a60 --- /dev/null +++ b/src/types/GitHubJsonWebToken.Types.ps1xml @@ -0,0 +1,19 @@ + + + + GitHubJsonWebToken + + + ExpiresIn + + if ($null -eq $this.ExpiresAt) { return } + $timeRemaining = $this.ExpiresAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining + + + + + diff --git a/src/types/GitHubRateLimitResource.Types.ps1xml b/src/types/GitHubRateLimitResource.Types.ps1xml new file mode 100644 index 000000000..1b3b538a3 --- /dev/null +++ b/src/types/GitHubRateLimitResource.Types.ps1xml @@ -0,0 +1,19 @@ + + + + GitHubRateLimitResource + + + ResetsIn + + if ($null -eq $this.ResetsAt) { return } + $timeRemaining = $this.ResetsAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining + + + + + diff --git a/tests/Apps.Tests.ps1 b/tests/Apps.Tests.ps1 index 9ab74a455..feb65b3d1 100644 --- a/tests/Apps.Tests.ps1 +++ b/tests/Apps.Tests.ps1 @@ -178,7 +178,7 @@ Describe 'Apps' { It 'Connect-GitHubApp - Connects as a GitHub App to ' { $context | Should -BeOfType 'InstallationGitHubContext' $context.ClientID | Should -Be $githubApp.ClientID - $context.TokenExpirationDate | Should -BeOfType [datetime] + $context.TokenExpiresAt | Should -BeOfType [datetime] $context.InstallationID | Should -BeOfType [uint64] $context.InstallationID | Should -BeGreaterThan 0 $context.Permissions | Should -BeOfType [PSCustomObject] @@ -202,6 +202,12 @@ Describe 'Apps' { $context.PerPage | Should -Be $config.PerPage } + It 'Connect-GitHubApp - TokenExpiresIn property should be calculated correctly' { + $context.TokenExpiresIn | Should -BeOfType [TimeSpan] + $context.TokenExpiresIn.TotalMinutes | Should -BeGreaterThan 0 + $context.TokenExpiresIn.TotalMinutes | Should -BeLessOrEqual 60 + } + It 'Revoked GitHub App token should fail on API call' -Skip:($TokenType -eq 'GITHUB_TOKEN') { $org = Get-GitHubOrganization -Name PSModule -Context $context $org | Should -Not -BeNullOrEmpty diff --git a/tests/GitHub.Tests.ps1 b/tests/GitHub.Tests.ps1 index 2338eff02..474160fbf 100644 --- a/tests/GitHub.Tests.ps1 +++ b/tests/GitHub.Tests.ps1 @@ -580,13 +580,53 @@ Describe 'API' { } } - Context 'Rate-Limit' { + Context 'RateLimit' { + BeforeAll { + $rateLimits = Get-GitHubRateLimit + } It 'Get-GitHubRateLimit - Gets the rate limit status for the authenticated user' { - $rateLimit = Get-GitHubRateLimit LogGroup 'RateLimit' { - Write-Host ($rateLimit | Format-Table | Out-String) + Write-Host ($rateLimits | Format-Table | Out-String) + } + $rateLimits | Should -Not -BeNullOrEmpty + } + + It 'Get-GitHubRateLimit - ResetsAt property should be a datetime' { + $rateLimit = $rateLimits | Select-Object -First 1 + $rateLimit.ResetsAt | Should -BeOfType [DateTime] + $rateLimit.ResetsAt | Should -BeGreaterThan ([DateTime]::Now) + } + + It 'Get-GitHubRateLimit - ResetsIn property should be calculated correctly' { + $rateLimit = $rateLimits | Select-Object -First 1 + $rateLimit.ResetsIn | Should -BeOfType [TimeSpan] + $rateLimit.ResetsIn.TotalSeconds | Should -BeGreaterThan 0 + $rateLimit.ResetsIn.TotalHours | Should -BeLessOrEqual 1 + } + + It 'Get-GitHubRateLimit - Should return objects with names core and rate' { + LogGroup 'RateLimit Names' { + Write-Host ($rateLimits.Name | Out-String) } - $rateLimit | Should -Not -BeNullOrEmpty + $rateLimits.Name | Should -Contain 'core' + $rateLimits.Name | Should -Contain 'rate' + } + + It 'Get-GitHubRateLimit - Objects should be of type GitHubRateLimitResource' { + $rateLimits | Should -BeOfType 'GitHubRateLimitResource' + } + + It 'Get-GitHubRateLimit - Should have correct property types for all objects' { + $rateLimits.Name | Should -BeOfType [String] + $rateLimits.Limit | Should -BeOfType [UInt64] + $rateLimits.Used | Should -BeOfType [UInt64] + $rateLimits.Remaining | Should -BeOfType [UInt64] + $rateLimits.ResetsAt | Should -BeOfType [DateTime] + $rateLimits.ResetsIn | Should -BeOfType [TimeSpan] + $rateLimits.Name | Should -Not -BeNullOrEmpty + $rateLimits.Limit | Should -BeGreaterOrEqual 0 + $rateLimits.Used | Should -BeGreaterOrEqual 0 + $rateLimits.Remaining | Should -BeGreaterOrEqual 0 } } From 7c13cbf205eb5720a51e3ef788e43b2c454c5bc9 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 13 Jul 2025 21:00:38 +0200 Subject: [PATCH 15/27] =?UTF-8?q?=F0=9F=AA=B2=20[Fix]:=20Remove=20unnecess?= =?UTF-8?q?ary=20skip=20configurations=20from=20PSModule.yml=20(#473)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request removes unnecessary test configurations and build settings from the `.github/PSModule.yml` file, streamlining the CI/CD pipeline. Streamlining CI/CD pipeline: * [`.github/PSModule.yml`](diffhunk://#diff-928165ed381f1982eb8f9746a59a2829db4abc8a28eddb8c109e12bb033ff96aL2-L24): Removed multiple test configurations (`SourceCode`, `PSModule`, `Module`, and `TestResults`) and build settings (`Docs`) that were set to be skipped, simplifying the file. ## Type of change - [ ] 📖 [Docs] - [x] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- .github/PSModule.yml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/PSModule.yml b/.github/PSModule.yml index d14ee6fa2..6d578178e 100644 --- a/.github/PSModule.yml +++ b/.github/PSModule.yml @@ -1,24 +1,3 @@ Test: - SourceCode: - Windows: - Skip: true - MacOS: - Skip: true - PSModule: - Windows: - Skip: true - MacOS: - Skip: true - Module: - Windows: - Skip: true - MacOS: - Skip: true - TestResults: - Skip: true CodeCoverage: - Skip: true PercentTarget: 50 -Build: - Docs: - Skip: true From aa23533310ec2e8787287ce41e50448f29092e1e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 14 Jul 2025 22:46:08 +0200 Subject: [PATCH 16/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Update=20format?= =?UTF-8?q?ting=20of=20`GitHubContext`=20and=20`GitHubRateLimitResource`?= =?UTF-8?q?=20(#474)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces updates to improve the handling and display of time-related properties in PowerShell scripts. The changes focus on replacing direct property access with the `Format-TimeSpan` function for better readability and consistency, while also adding color-coded visual indicators for certain time-related values. ### Time property updates: * 🪲 `src/formats/GitHubContext.Format.ps1xml`: Replaced `Remaining` with `TokenExpiresIn` for time calculations and display, and formatted the output using `Format-TimeSpan` for improved readability. * 🩹 `src/formats/GitHubRateLimitResource.Format.ps1xml`: Added a `ScriptBlock` to format the `ResetsIn` property using `Format-TimeSpan`. Introduced color-coded visual indicators for `ResetsIn` values based on their proximity to expiration, enhancing the user experience. ### Dependency update: * `src/header.ps1`: Added a `#Requires` directive for the `TimeSpan` module with version `3.0.0` to ensure compatibility with the new `Format-TimeSpan` function. ## Type of change - [ ] 📖 [Docs] - [x] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- src/classes/public/GitHubFormatter.ps1 | 22 +++++++++++++ src/formats/GitHubContext.Format.ps1xml | 33 +++++-------------- .../GitHubRateLimitResource.Format.ps1xml | 28 +++++++++++++++- src/header.ps1 | 4 ++- 4 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 src/classes/public/GitHubFormatter.ps1 diff --git a/src/classes/public/GitHubFormatter.ps1 b/src/classes/public/GitHubFormatter.ps1 new file mode 100644 index 000000000..73c742d1e --- /dev/null +++ b/src/classes/public/GitHubFormatter.ps1 @@ -0,0 +1,22 @@ +class GitHubFormatter { + static [string] FormatColorByRatio([double]$Ratio, [string]$Text) { + $Ratio = [Math]::Min([Math]::Max($Ratio, 0), 1) + + if ($Ratio -ge 1) { + $r = 0 + $g = 255 + } elseif ($Ratio -le 0) { + $r = 255 + $g = 0 + } elseif ($Ratio -ge 0.5) { + $r = [Math]::Round(255 * (2 - 2 * $Ratio)) + $g = 255 + } else { + $r = 255 + $g = [Math]::Round(255 * (2 * $Ratio)) + } + $color = "`e[38;2;$r;$g;0m" + $reset = "`e[0m" + return "$color$Text$reset" + } +} diff --git a/src/formats/GitHubContext.Format.ps1xml b/src/formats/GitHubContext.Format.ps1xml index 363dfceed..fcbfea9eb 100644 --- a/src/formats/GitHubContext.Format.ps1xml +++ b/src/formats/GitHubContext.Format.ps1xml @@ -54,45 +54,28 @@ - if ($null -eq $_.Remaining) { + if ($null -eq $_.TokenExpiresIn) { return } - if ($_.Remaining -lt 0) { - $text = "Expired" + if ($_.TokenExpiresIn -lt 0) { + $text = 'Expired' } else { - $text = "$($_.Remaining.Hours)h $($_.Remaining.Minutes)m - $($_.Remaining.Seconds)s" + $text = $_.TokenExpiresIn.ToString('hh\:mm\:ss') } if ($Host.UI.SupportsVirtualTerminal -and ($env:GITHUB_ACTIONS -ne 'true')) { switch ($_.AuthType) { 'UAT' { - $MaxValue = [TimeSpan]::FromHours(8) + $maxValue = [TimeSpan]::FromHours(8) } 'IAT' { - $MaxValue = [TimeSpan]::FromHours(1) + $maxValue = [TimeSpan]::FromHours(1) } } - $ratio = [Math]::Min(($_.Remaining / $MaxValue), 1) - - if ($ratio -ge 1) { - $r = 0 - $g = 255 - } elseif ($ratio -le 0) { - $r = 255 - $g = 0 - } elseif ($ratio -ge 0.5) { - $r = [Math]::Round(255 * (2 - 2 * $ratio)) - $g = 255 - } else { - $r = 255 - $g = [Math]::Round(255 * (2 * $ratio)) - } - $b = 0 - $color = $PSStyle.Foreground.FromRgb($r, $g, $b) - "$color$text$($PSStyle.Reset)" + $ratio = [Math]::Min(($_.TokenExpiresIn / $maxValue), 1) + [GitHubFormatter]::FormatColorByRatio($ratio, $text) } else { $text } diff --git a/src/formats/GitHubRateLimitResource.Format.ps1xml b/src/formats/GitHubRateLimitResource.Format.ps1xml index b9e4bdc9d..51b413d3f 100644 --- a/src/formats/GitHubRateLimitResource.Format.ps1xml +++ b/src/formats/GitHubRateLimitResource.Format.ps1xml @@ -46,7 +46,33 @@ ResetsAt - ResetsIn + + if ($null -eq $_.ResetsIn) { + return + } + + if ($_.ResetsIn -lt 0) { + $text = 'Expired' + } else { + $text = $_.ResetsIn.ToString('hh\:mm\:ss') + } + + if ($Host.UI.SupportsVirtualTerminal -and + ($env:GITHUB_ACTIONS -ne 'true')) { + if ($_.Name -in @('source_import', + 'dependency_snapshots', 'code_scanning_autofix', 'search', + 'dependency_sbom', 'code_search')) { + $maxValue = [TimeSpan]::FromMinutes(1) + } else { + $maxValue = [TimeSpan]::FromHours(1) + } + + $ratio = [Math]::Min(($_.ResetsIn / $maxValue), 1) + [GitHubFormatter]::FormatColorByRatio($ratio, $text) + } else { + $text + } + diff --git a/src/header.ps1 b/src/header.ps1 index cc1fde9ac..9b563d153 100644 --- a/src/header.ps1 +++ b/src/header.ps1 @@ -1,3 +1,5 @@ -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains long links.')] +#Requires -Modules @{ ModuleName = 'TimeSpan'; RequiredVersion = '3.0.1' } + +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains long links.')] [CmdletBinding()] param() From 2575b039862f1046d92cc472666d7973dce11a61 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Tue, 15 Jul 2025 13:14:05 +0200 Subject: [PATCH 17/27] =?UTF-8?q?=F0=9F=AA=B2[Fix]:=20Fix=20output=20forma?= =?UTF-8?q?tting=20of=20Release=20Assets=20(#476)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request enhances the handling of `GitHubReleaseAsset` objects and their formatting, improves the readability of file size values, and adds new tests for pipeline functionality. The most important changes include the addition of a file size formatting method, updates to constructors for `GitHubReleaseAsset`, and the creation of a new XML-based table view for release assets. ### Enhancements to `GitHubReleaseAsset` handling * Updated constructors across multiple files to use `[GitHubReleaseAsset]::new` instead of direct object casting, ensuring consistency and clarity in object creation. ### File size formatting improvements * Added a static `FormatFileSize` method to `GitHubFormatter` for converting file sizes into human-readable formats (e.g., KB, MB, GB, TB). ### XML-based table view for release assets * Introduced a new XML view definition (`GitHubReleaseAssetTable`) to display release asset details in a tabular format, including columns for name, state, size, downloads, creation date, and update date. ### Improved datetime handling * Simplified `CreatedAt` and `UpdatedAt` properties by removing explicit `DateTime.Parse` calls, relying on native datetime parsing. ### New tests for pipeline functionality * Added tests to verify that `Get-GitHubReleaseAsset` retrieves assets correctly when used in a pipeline, validating properties such as ID, name, size, and datetime fields. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code. - [x] I have commented my code, particularly in hard-to-understand areas. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/classes/public/GitHubFormatter.ps1 | 10 +++ .../public/Releases/GitHubReleaseAsset.ps1 | 8 +-- src/formats/GitHubReleaseAsset.Format.ps1xml | 68 +++++++++++++++++++ .../Assets/Get-GitHubReleaseAssetByID.ps1 | 2 +- .../Get-GitHubReleaseAssetByReleaseID.ps1 | 4 +- .../Assets/Add-GitHubReleaseAsset.ps1 | 2 +- .../Assets/Update-GitHubReleaseAsset.ps1 | 2 +- tests/Releases.Tests.ps1 | 27 ++++++++ 8 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 src/formats/GitHubReleaseAsset.Format.ps1xml diff --git a/src/classes/public/GitHubFormatter.ps1 b/src/classes/public/GitHubFormatter.ps1 index 73c742d1e..ce5f49087 100644 --- a/src/classes/public/GitHubFormatter.ps1 +++ b/src/classes/public/GitHubFormatter.ps1 @@ -19,4 +19,14 @@ $reset = "`e[0m" return "$color$Text$reset" } + + static [string] FormatFileSize([long]$size) { + switch ($size) { + { $_ -ge 1TB } { return '{0:N2} TB' -f ($size / 1TB) } + { $_ -ge 1GB } { return '{0:N2} GB' -f ($size / 1GB) } + { $_ -ge 1MB } { return '{0:N2} MB' -f ($size / 1MB) } + { $_ -ge 1KB } { return '{0:N2} KB' -f ($size / 1KB) } + } + return "$size B" + } } diff --git a/src/classes/public/Releases/GitHubReleaseAsset.ps1 b/src/classes/public/Releases/GitHubReleaseAsset.ps1 index c0ae6d74b..fac713cfe 100644 --- a/src/classes/public/Releases/GitHubReleaseAsset.ps1 +++ b/src/classes/public/Releases/GitHubReleaseAsset.ps1 @@ -52,8 +52,8 @@ $this.ContentType = $Object.content_type $this.Size = $Object.size $this.Downloads = $Object.download_count - $this.CreatedAt = [datetime]::Parse($Object.created_at) - $this.UpdatedAt = [datetime]::Parse($Object.updated_at) + $this.CreatedAt = $Object.created_at + $this.UpdatedAt = $Object.updated_at $this.UploadedBy = [GitHubUser]::new($Object.uploader) } else { $this.NodeID = $Object.id @@ -62,8 +62,8 @@ $this.ContentType = $Object.contentType $this.Size = $Object.size $this.Downloads = $Object.downloadCount - $this.CreatedAt = [datetime]::Parse($Object.createdAt) - $this.UpdatedAt = [datetime]::Parse($Object.updatedAt) + $this.CreatedAt = $Object.createdAt + $this.UpdatedAt = $Object.updatedAt $this.UploadedBy = [GitHubUser]::new($Object.uploadedBy) } } diff --git a/src/formats/GitHubReleaseAsset.Format.ps1xml b/src/formats/GitHubReleaseAsset.Format.ps1xml new file mode 100644 index 000000000..d1e9978d5 --- /dev/null +++ b/src/formats/GitHubReleaseAsset.Format.ps1xml @@ -0,0 +1,68 @@ + + + + + GitHubReleaseAssetTable + + GitHubReleaseAsset + + + + + + + + + + + + + + + + + + + + + + + + + + + + if ($Host.UI.SupportsVirtualTerminal -and + ($env:GITHUB_ACTIONS -ne 'true')) { + $PSStyle.FormatHyperlink($_.Name,$_.Url) + } else { + $_.Name + } + + + + State + + + + [GitHubFormatter]::FormatFileSize($_.Size) + + Right + + + Downloads + Right + + + CreatedAt + + + UpdatedAt + + + + + + + + diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 index dc7e238b9..71a9a4053 100644 --- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 +++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 @@ -55,7 +55,7 @@ } Invoke-GitHubAPI @apiParams | ForEach-Object { - [GitHubReleaseAsset]($_.Response) + [GitHubReleaseAsset]::new($_.Response) } } diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 index c8215d842..6d81aeace 100644 --- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 +++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 @@ -66,11 +66,11 @@ foreach ($asset in $_.Response) { if ($PSBoundParameters.ContainsKey('Name')) { if ($asset.name -eq $Name) { - [GitHubReleaseAsset]($asset) + [GitHubReleaseAsset]::new($asset) break } } else { - [GitHubReleaseAsset]($asset) + [GitHubReleaseAsset]::new($asset) } } } diff --git a/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 index 1986d386f..5e9832840 100644 --- a/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 @@ -181,7 +181,7 @@ } Invoke-GitHubAPI @apiParams | ForEach-Object { - [GitHubReleaseAsset]($_.Response) + [GitHubReleaseAsset]::new($_.Response) } } diff --git a/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 index d07cdfdc0..ac95ac0d5 100644 --- a/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 +++ b/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1 @@ -83,7 +83,7 @@ if ($PSCmdlet.ShouldProcess("assets for release with ID [$ID] in [$Owner/$Repository]", 'Set')) { Invoke-GitHubAPI @apiParams | ForEach-Object { - [GitHubReleaseAsset]($_.Response) + [GitHubReleaseAsset]::new($_.Response) } } } diff --git a/tests/Releases.Tests.ps1 b/tests/Releases.Tests.ps1 index 2837cabb6..3dd9f843f 100644 --- a/tests/Releases.Tests.ps1 +++ b/tests/Releases.Tests.ps1 @@ -644,6 +644,33 @@ ID,Name,Value Test-Path -Path $downloadedFile.FullName | Should -BeTrue $downloadedFile.Name | Should -Be $asset.Name } + + It 'Get-GitHubReleaseAsset - Gets assets from release using pipeline' { + $assets = Get-GitHubRelease -Owner ryanoasis -Repository nerd-fonts | Get-GitHubReleaseAsset + LogGroup 'Release assets from pipeline' { + Write-Host ($assets | Format-List -Property * | Out-String) + } + $assets | Should -Not -BeNullOrEmpty + $assets.Count | Should -BeGreaterThan 0 + foreach ($asset in $assets) { + $asset | Should -BeOfType [GitHubReleaseAsset] + $asset.ID | Should -Not -BeNullOrEmpty + $asset.NodeID | Should -Not -BeNullOrEmpty + $asset.Url | Should -Not -BeNullOrEmpty + $asset.Name | Should -Not -BeNullOrEmpty + # $asset.Label | Should -Not -BeNullOrEmpty - Label is optional and may not be set + $asset.State | Should -Be 'uploaded' + $asset.ContentType | Should -Not -BeNullOrEmpty + $asset.Size | Should -BeGreaterOrEqual 0 + $asset.Downloads | Should -BeGreaterOrEqual 0 + $asset.CreatedAt | Should -Not -BeNullOrEmpty + $asset.CreatedAt | Should -BeOfType 'DateTime' + $asset.UpdatedAt | Should -Not -BeNullOrEmpty + $asset.UpdatedAt | Should -BeOfType 'DateTime' + $asset.UploadedBy | Should -Not -BeNullOrEmpty + $asset.UploadedBy | Should -BeOfType 'GitHubUser' + } + } } } } From 67650ba9c78993f85daed0620fcb34b367a25277 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 16 Jul 2025 17:57:50 +0200 Subject: [PATCH 18/27] =?UTF-8?q?=F0=9F=9A=80=20[Feature]:=20Refactor=20`C?= =?UTF-8?q?ontext`=20classes=20and=20separate=20JWT=20Creation=20and=20Sig?= =?UTF-8?q?ning=20Logic=20(#477)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces several changes to enhance GitHub context classes, improve JWT handling. Key updates include renaming classes for consistency, adding token expiration handling, and refactoring JWT-related functionality by splitting it into modular functions. - Fixes #471 ### Improvements to JWT handling * Removed the `GitHubJsonWebToken` class, simplifying the JWT implementation. * Introduced modular private functions for JWT management: - `New-GitHubUnsignedJWT`: Generates an unsigned JWT with header and payload. - `Add-GitHubJWTSignature`: Signs an unsigned JWT using an RSA private key. * Removed the monolithic `Get-GitHubAppJSONWebToken` function, replacing it with the modular approach. * Added `Update-GitHubAppJWT` to handle JWT updates for the `GitHubAppContext` type. ### Enhancements to GitHub classes * 🌟 Renamed context classes for consistency, and updated the belonging format files: - `AppGitHubContext` → `GitHubAppContext` - `InstallationGitHubContext` → `GitHubAppInstallationContext` - `UserGitHubContext` → `GitHubUserContext` * 🌟 The context property value of `TokenType` on `GitHubAppContext` is renamed from 'PEM' to 'JWT' to correctly represent the type of the Token property. * Moved `TokenExpiresAt` property to the `GitHubContext` class to store token expiration dates. * All types that previously added a `ScriptProperty` that copied the value of another, is now converted to a `AliasProperty`. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/classes/public/Context/GitHubContext.ps1 | 6 +- ...GitHubContext.ps1 => GitHubAppContext.ps1} | 7 +- ...t.ps1 => GitHubAppInstallationContext.ps1} | 12 +- ...itHubContext.ps1 => GitHubUserContext.ps1} | 12 +- src/classes/public/GitHubJsonWebToken.ps1 | 15 -- src/formats/GitHubContext.Format.ps1xml | 18 +-- .../GitHub Apps/Add-GitHubJWTSignature.ps1 | 73 ++++++++++ .../GitHub Apps/Get-GitHubAppJSONWebToken.ps1 | 134 ------------------ .../GitHub Apps/New-GitHubUnsignedJWT.ps1 | 76 ++++++++++ .../Apps/GitHub Apps/Update-GitHubAppJWT.ps1 | 69 +++++++++ .../Auth/Context/Resolve-GitHubContext.ps1 | 9 +- .../Update-GitHubUserAccessToken.ps1 | 21 ++- .../public/Auth/Connect-GitHubAccount.ps1 | 2 +- .../public/Auth/Connect-GitHubApp.ps1 | 2 +- .../public/Auth/Context/Get-GitHubContext.ps1 | 8 +- .../public/Auth/Disconnect-GitHubAccount.ps1 | 2 +- src/types/GitHubContext.Types.ps1xml | 4 +- src/types/GitHubEnvironment.Types.ps1xml | 6 +- src/types/GitHubJsonWebToken.Types.ps1xml | 19 --- src/types/GitHubNode.Types.ps1xml | 6 +- src/types/GitHubOrganization.Types.ps1xml | 6 +- src/types/GitHubOwner.Types.ps1xml | 6 +- src/types/GitHubRelease.Types.ps1xml | 6 +- src/types/GitHubRepository.Types.ps1xml | 6 +- src/types/GitHubTeam.Types.ps1xml | 6 +- src/types/GitHubUser.Types.ps1xml | 18 +-- src/types/GitHubWorkflow.Types.ps1xml | 6 +- src/types/GitHubWorkflowRun.Types.ps1xml | 6 +- tests/Apps.Tests.ps1 | 2 +- tests/Data/AuthCases.ps1 | 6 +- 30 files changed, 311 insertions(+), 258 deletions(-) rename src/classes/public/Context/GitHubContext/{AppGitHubContext.ps1 => GitHubAppContext.ps1} (89%) rename src/classes/public/Context/GitHubContext/{InstallationGitHubContext.ps1 => GitHubAppInstallationContext.ps1} (86%) rename src/classes/public/Context/GitHubContext/{UserGitHubContext.ps1 => GitHubUserContext.ps1} (86%) delete mode 100644 src/classes/public/GitHubJsonWebToken.ps1 create mode 100644 src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 delete mode 100644 src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 create mode 100644 src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 create mode 100644 src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 delete mode 100644 src/types/GitHubJsonWebToken.Types.ps1xml diff --git a/src/classes/public/Context/GitHubContext.ps1 b/src/classes/public/Context/GitHubContext.ps1 index 4eaee6d32..8788d051b 100644 --- a/src/classes/public/Context/GitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext.ps1 @@ -44,9 +44,13 @@ [securestring] $Token # The token type. - # ghu / gho / ghp / github_pat / PEM / ghs / + # ghu / gho / ghp / github_pat / JWT / ghs / [string] $TokenType + # The token expiration date. + # 2024-01-01-00:00:00 + [System.Nullable[datetime]] $TokenExpiresAt + # The default value for the Enterprise parameter. [string] $Enterprise diff --git a/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 similarity index 89% rename from src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 rename to src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 index 98e1aa4b0..6f9995e5b 100644 --- a/src/classes/public/Context/GitHubContext/AppGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 @@ -1,4 +1,4 @@ -class AppGitHubContext : GitHubContext { +class GitHubAppContext : GitHubContext { # Client ID for GitHub Apps [string] $ClientID @@ -17,9 +17,9 @@ # The events that the app is subscribing to once installed [string[]] $Events - AppGitHubContext() {} + GitHubAppContext() {} - AppGitHubContext([pscustomobject]$Object) { + GitHubAppContext([pscustomobject]$Object) { $this.ID = $Object.ID $this.Name = $Object.Name $this.DisplayName = $Object.DisplayName @@ -33,6 +33,7 @@ $this.UserName = $Object.UserName $this.Token = $Object.Token $this.TokenType = $Object.TokenType + $this.TokenExpiresAt = $Object.TokenExpiresAt $this.Enterprise = $Object.Enterprise $this.Owner = $Object.Owner $this.Repository = $Object.Repository diff --git a/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/GitHubAppInstallationContext.ps1 similarity index 86% rename from src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 rename to src/classes/public/Context/GitHubContext/GitHubAppInstallationContext.ps1 index 2f0ae9764..2b817f3ec 100644 --- a/src/classes/public/Context/GitHubContext/InstallationGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/GitHubAppInstallationContext.ps1 @@ -1,11 +1,7 @@ -class InstallationGitHubContext : GitHubContext { +class GitHubAppInstallationContext : GitHubContext { # Client ID for GitHub Apps [string] $ClientID - # The token expiration date. - # 2024-01-01-00:00:00 - [System.Nullable[datetime]] $TokenExpiresAt - # The installation ID. [System.Nullable[uint64]] $InstallationID @@ -21,9 +17,9 @@ # The target login or slug of the installation. [string] $InstallationName - InstallationGitHubContext() {} + GitHubAppInstallationContext() {} - InstallationGitHubContext([pscustomobject]$Object) { + GitHubAppInstallationContext([pscustomobject]$Object) { $this.ID = $Object.ID $this.Name = $Object.Name $this.DisplayName = $Object.DisplayName @@ -37,13 +33,13 @@ $this.UserName = $Object.UserName $this.Token = $Object.Token $this.TokenType = $Object.TokenType + $this.TokenExpiresAt = $Object.TokenExpiresAt $this.Enterprise = $Object.Enterprise $this.Owner = $Object.Owner $this.Repository = $Object.Repository $this.HttpVersion = $Object.HttpVersion $this.PerPage = $Object.PerPage $this.ClientID = $Object.ClientID - $this.TokenExpiresAt = $Object.TokenExpiresAt $this.InstallationID = $Object.InstallationID $this.Permissions = $Object.Permissions $this.Events = $Object.Events diff --git a/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 b/src/classes/public/Context/GitHubContext/GitHubUserContext.ps1 similarity index 86% rename from src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 rename to src/classes/public/Context/GitHubContext/GitHubUserContext.ps1 index 0a769b13f..fa493984e 100644 --- a/src/classes/public/Context/GitHubContext/UserGitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext/GitHubUserContext.ps1 @@ -1,4 +1,4 @@ -class UserGitHubContext : GitHubContext { +class GitHubUserContext : GitHubContext { # The authentication client ID. # Client ID for UAT [string] $AuthClientID @@ -11,10 +11,6 @@ # 'gist read:org repo workflow' [string] $Scope - # The token expiration date. - # 2024-01-01-00:00:00 - [System.Nullable[datetime]] $TokenExpiresAt - # The refresh token. [securestring] $RefreshToken @@ -22,9 +18,9 @@ # 2024-01-01-00:00:00 [System.Nullable[datetime]] $RefreshTokenExpiresAt - UserGitHubContext() {} + GitHubUserContext() {} - UserGitHubContext([PSCustomObject]$Object) { + GitHubUserContext([PSCustomObject]$Object) { $this.ID = $Object.ID $this.Name = $Object.Name $this.DisplayName = $Object.DisplayName @@ -38,6 +34,7 @@ $this.UserName = $Object.UserName $this.Token = $Object.Token $this.TokenType = $Object.TokenType + $this.TokenExpiresAt = $Object.TokenExpiresAt $this.Enterprise = $Object.Enterprise $this.Owner = $Object.Owner $this.Repository = $Object.Repository @@ -46,7 +43,6 @@ $this.AuthClientID = $Object.AuthClientID $this.DeviceFlowType = $Object.DeviceFlowType $this.Scope = $Object.Scope - $this.TokenExpiresAt = $Object.TokenExpiresAt $this.RefreshToken = $Object.RefreshToken $this.RefreshTokenExpiresAt = $Object.RefreshTokenExpiresAt } diff --git a/src/classes/public/GitHubJsonWebToken.ps1 b/src/classes/public/GitHubJsonWebToken.ps1 deleted file mode 100644 index b98b9d99c..000000000 --- a/src/classes/public/GitHubJsonWebToken.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -class GitHubJsonWebToken { - # The secure JWT string used for GitHub API authentication - [securestring] $Token - - # The timestamp when this token was issued (in UTC) - [DateTime] $IssuedAt - - # The timestamp when this token will expire (in UTC) - [DateTime] $ExpiresAt - - # The ClientID for the GitHub App - [string] $Issuer - - GitHubJsonWebToken() {} -} diff --git a/src/formats/GitHubContext.Format.ps1xml b/src/formats/GitHubContext.Format.ps1xml index fcbfea9eb..90ae28648 100644 --- a/src/formats/GitHubContext.Format.ps1xml +++ b/src/formats/GitHubContext.Format.ps1xml @@ -4,9 +4,9 @@ GitHubContextTableView - AppGitHubContext - InstallationGitHubContext - UserGitHubContext + GitHubAppContext + GitHubAppInstallationContext + GitHubUserContext GitHubContext @@ -152,9 +152,9 @@ - AppGitHubContextListView + GitHubAppContextListView - AppGitHubContext + GitHubAppContext @@ -217,9 +217,9 @@ - InstallationGitHubContextListView + GitHubAppInstallationContextListView - InstallationGitHubContext + GitHubAppInstallationContext @@ -291,9 +291,9 @@ - UserGitHubContextListView + GitHubUserContextListView - UserGitHubContext + GitHubUserContext diff --git a/src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 b/src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 new file mode 100644 index 000000000..f00d160da --- /dev/null +++ b/src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 @@ -0,0 +1,73 @@ +function Add-GitHubJWTSignature { + <# + .SYNOPSIS + Signs a JSON Web Token (JWT) using a local RSA private key. + + .DESCRIPTION + Takes an unsigned JWT (header.payload) and adds a signature using the provided RSA private key. + This function handles the RSA signing process and returns the complete signed JWT. + + .EXAMPLE + Add-GitHubJWTSignature -UnsignedJWT 'eyJ0eXAiOi...' -PrivateKey '--- BEGIN RSA PRIVATE KEY --- ... --- END RSA PRIVATE KEY ---' + + Adds a signature to the unsigned JWT using the provided private key. + + .OUTPUTS + String + + .NOTES + This function isolates the signing logic to enable support for multiple signing methods. + + .LINK + https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Add-GitHubJWTSignature + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', + '', + Justification = 'Used to handle secure string private keys.' + )] + [CmdletBinding()] + [OutputType([string])] + param( + # The unsigned JWT (header.payload) to sign. + [Parameter(Mandatory)] + [string] $UnsignedJWT, + + # The private key of the GitHub App. + [Parameter(Mandatory)] + [object] $PrivateKey + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + if ($PrivateKey -is [securestring]) { + $PrivateKey = $PrivateKey | ConvertFrom-SecureString -AsPlainText + } + + $rsa = [System.Security.Cryptography.RSA]::Create() + $rsa.ImportFromPem($PrivateKey) + + try { + $signature = [Convert]::ToBase64String( + $rsa.SignData( + [System.Text.Encoding]::UTF8.GetBytes($UnsignedJWT), + [System.Security.Cryptography.HashAlgorithmName]::SHA256, + [System.Security.Cryptography.RSASignaturePadding]::Pkcs1 + ) + ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + return "$UnsignedJWT.$signature" + } finally { + if ($rsa) { + $rsa.Dispose() + } + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 deleted file mode 100644 index 9ac33c835..000000000 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppJSONWebToken.ps1 +++ /dev/null @@ -1,134 +0,0 @@ -function Get-GitHubAppJSONWebToken { - <# - .SYNOPSIS - Generates a JSON Web Token (JWT) for a GitHub App. - - .DESCRIPTION - Generates a JSON Web Token (JWT) for a GitHub App. - - .EXAMPLE - Get-GitHubAppJWT -ClientId 'Iv987654321' -PrivateKeyFilePath '/path/to/private-key.pem' - - Generates a JSON Web Token (JWT) for a GitHub App using the specified client ID and private key file path. - - .EXAMPLE - Get-GitHubAppJWT -ClientId 'Iv987654321' -PrivateKey '--- BEGIN RSA PRIVATE KEY --- ... --- END RSA PRIVATE KEY ---' - - Generates a JSON Web Token (JWT) for a GitHub App using the specified client ID and private key. - - .OUTPUTS - GitHubJsonWebToken - - .NOTES - [Generating a JSON Web Token (JWT) for a GitHub App | GitHub Docs](https://docs.github.com/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-powershell-to-generate-a-jwt) - - .LINK - https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Get-GitHubAppJSONWebToken - #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute( - 'PSAvoidLongLines', - '', - Justification = 'Contains a long link.' - )] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute( - 'PSAvoidUsingConvertToSecureStringWithPlainText', - '', - Justification = 'Generated JWT is a plaintext string.' - )] - - [CmdletBinding(DefaultParameterSetName = 'PrivateKey')] - [OutputType([GitHubJsonWebToken])] - param( - # The client ID of the GitHub App. - # Can use the GitHub App ID or the client ID. - [Parameter(Mandatory)] - [string] $ClientId, - - # The path to the private key file of the GitHub App. - [Parameter( - Mandatory, - ParameterSetName = 'FilePath' - )] - [string] $PrivateKeyFilePath, - - # The private key of the GitHub App. - [Parameter( - Mandatory, - ParameterSetName = 'PrivateKey' - )] - [object] $PrivateKey - ) - - begin { - $stackPath = Get-PSCallStackPath - Write-Debug "[$stackPath] - Start" - } - - process { - if ($PrivateKeyFilePath) { - if (-not (Test-Path -Path $PrivateKeyFilePath)) { - throw "The private key path [$PrivateKeyFilePath] does not exist." - } - - $PrivateKey = Get-Content -Path $PrivateKeyFilePath -Raw - } - - if ($PrivateKey -is [securestring]) { - $PrivateKey = $PrivateKey | ConvertFrom-SecureString -AsPlainText - } - - $header = [Convert]::ToBase64String( - [System.Text.Encoding]::UTF8.GetBytes( - ( - ConvertTo-Json -InputObject @{ - alg = 'RS256' - typ = 'JWT' - } - ) - ) - ).TrimEnd('=').Replace('+', '-').Replace('/', '_') - - $iat = [System.DateTimeOffset]::UtcNow.AddSeconds(-$script:GitHub.Config.JwtTimeTolerance).ToUnixTimeSeconds() - $exp = [System.DateTimeOffset]::UtcNow.AddSeconds($script:GitHub.Config.JwtTimeTolerance).ToUnixTimeSeconds() - $payload = [Convert]::ToBase64String( - [System.Text.Encoding]::UTF8.GetBytes( - ( - ConvertTo-Json -InputObject @{ - iat = $iat - exp = $exp - iss = $ClientId - } - ) - ) - ).TrimEnd('=').Replace('+', '-').Replace('/', '_') - - $rsa = [System.Security.Cryptography.RSA]::Create() - $rsa.ImportFromPem($PrivateKey) - - $signature = [Convert]::ToBase64String( - $rsa.SignData( - [System.Text.Encoding]::UTF8.GetBytes("$header.$payload"), - [System.Security.Cryptography.HashAlgorithmName]::SHA256, - [System.Security.Cryptography.RSASignaturePadding]::Pkcs1 - ) - ).TrimEnd('=').Replace('+', '-').Replace('/', '_') - $jwt = "$header.$payload.$signature" - [GitHubJsonWebToken]@{ - Token = ConvertTo-SecureString -String $jwt -AsPlainText - IssuedAt = [DateTime]::UnixEpoch.AddSeconds($iat) - ExpiresAt = [DateTime]::UnixEpoch.AddSeconds($exp) - Issuer = $ClientId - } - } - - end { - Write-Debug "[$stackPath] - End" - } - - clean { - Remove-Variable -Name jwt -ErrorAction SilentlyContinue - Remove-Variable -Name rsa -ErrorAction SilentlyContinue - Remove-Variable -Name signature -ErrorAction SilentlyContinue - [System.GC]::Collect() - } -} diff --git a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 new file mode 100644 index 000000000..5332505c5 --- /dev/null +++ b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 @@ -0,0 +1,76 @@ +function New-GitHubUnsignedJWT { + <# + .SYNOPSIS + Creates an unsigned JSON Web Token (JWT) for a GitHub App. + + .DESCRIPTION + Creates the header and payload portions of a JSON Web Token (JWT) for a GitHub App. + This function does not sign the JWT - it returns the unsigned token (header.payload) + that can be passed to a signing function. + + .EXAMPLE + New-GitHubUnsignedJWT -ClientId 'Iv987654321' + + Creates an unsigned JWT for a GitHub App using the specified client ID. + + .OUTPUTS + String + + .NOTES + This function generates a JWT for a GitHub App that can be signed using a private key. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseShouldProcessForStateChangingFunctions', '', + Justification = 'Function creates an unsigned JWT without modifying system state' + )] + [CmdletBinding()] + [OutputType([pscustomobject])] + param( + # The client ID of the GitHub App. + # Can use the GitHub App ID or the client ID. + [Parameter(Mandatory)] + [string] $ClientID + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + $header = [Convert]::ToBase64String( + [System.Text.Encoding]::UTF8.GetBytes( + ( + ConvertTo-Json -InputObject @{ + alg = 'RS256' + typ = 'JWT' + } + ) + ) + ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + $now = [System.DateTimeOffset]::UtcNow + $iat = $now.AddSeconds(-$script:GitHub.Config.JwtTimeTolerance) + $exp = $now.AddSeconds($script:GitHub.Config.JwtTimeTolerance) + $payload = [Convert]::ToBase64String( + [System.Text.Encoding]::UTF8.GetBytes( + ( + ConvertTo-Json -InputObject @{ + iat = $iat.ToUnixTimeSeconds() + exp = $exp.ToUnixTimeSeconds() + iss = $ClientID + } + ) + ) + ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + [pscustomobject]@{ + Base = "$header.$payload" + IssuedAt = $iat.DateTime + ExpiresAt = $exp.DateTime + Issuer = $ClientID + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 b/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 new file mode 100644 index 000000000..de4ce05d4 --- /dev/null +++ b/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 @@ -0,0 +1,69 @@ +function Update-GitHubAppJWT { + <# + .SYNOPSIS + Updates a JSON Web Token (JWT) for a GitHub App context. + + .DESCRIPTION + Updates a JSON Web Token (JWT) for a GitHub App context. + + .EXAMPLE + Update-GitHubAppJWT -Context $Context + + Updates the JSON Web Token (JWT) for a GitHub App using the specified context. + + .OUTPUTS + securestring + + .NOTES + [Generating a JSON Web Token (JWT) for a GitHub App | GitHub Docs](https://docs.github.com/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-powershell-to-generate-a-jwt) + + .LINK + https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Update-GitHubAppJWT + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', '', + Justification = 'Contains a long link.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'Generated JWT is a plaintext string.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseShouldProcessForStateChangingFunctions', '', + Justification = 'Function creates a JWT without modifying system state' + )] + [CmdletBinding()] + [OutputType([object])] + param( + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context, + + # Return the updated context. + [Parameter()] + [switch] $PassThru + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + $unsignedJWT = New-GitHubUnsignedJWT -ClientId $Context.ClientID + $jwt = Add-GitHubJWTSignature -UnsignedJWT $unsignedJWT.Base -PrivateKey $Context.PrivateKey + $Context.Token = ConvertTo-SecureString -String $jwt -AsPlainText + $Context.TokenExpiresAt = $unsignedJWT.ExpiresAt + if ($Context.ID) { + $Context = Set-Context -Context $Context -Vault $script:GitHub.ContextVault -PassThru + } + if ($PassThru) { + $Context + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 index 5b2253b53..a089f6add 100644 --- a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 @@ -66,13 +66,12 @@ switch ($Context.TokenType) { 'ghu' { - Write-Verbose 'Using GitHub User Access Token.' + Write-Verbose 'Update GitHub User Access Token.' $Context = Update-GitHubUserAccessToken -Context $Context -PassThru } - 'PEM' { - Write-Verbose 'Using GitHub App PEM Token.' - $jwt = Get-GitHubAppJSONWebToken -ClientId $Context.ClientID -PrivateKey $Context.PrivateKey - $Context.Token = $jwt.Token + 'JWT' { + Write-Verbose 'Update GitHub App JWT Token.' + $Context = Update-GitHubAppJWT -Context $Context -PassThru } } diff --git a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 index 6fba80ca1..4f4ce2ffe 100644 --- a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 @@ -21,16 +21,25 @@ #> [CmdletBinding(SupportsShouldProcess)] [OutputType([GitHubContext])] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Is the CLI part of the module.')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'The tokens are recieved as clear text. Mitigating exposure by removing variables and performing garbage collection.')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Reason for suppressing')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Is the CLI part of the module.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'The tokens are recieved as clear text. Mitigating exposure by removing variables and performing garbage collection.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', '', + Justification = 'Reason for suppressing' + )] param( # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. [Parameter(Mandatory)] [object] $Context, - # Return the new access token. + # Return the updated context. [Parameter()] [switch] $PassThru, @@ -87,7 +96,6 @@ Write-Verbose "Access token is not valid. Waiting for mutex to be released (timeout: $($TimeoutMs)ms)..." try { if ($lock.WaitOne($TimeoutMs)) { - # Re-read context to get updated token from other process $Context = Resolve-GitHubContext -Context $Context.ID $lock.ReleaseMutex() } else { @@ -95,7 +103,7 @@ } } catch [System.Threading.AbandonedMutexException] { Write-Debug 'Mutex was abandoned by another process. Re-checking token state...' - $Context = Get-Context -Context $Context.ID -Vault $script:GitHub.ContextVault + $Context = Resolve-GitHubContext -Context $Context.ID } } } finally { @@ -113,4 +121,3 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } diff --git a/src/functions/public/Auth/Connect-GitHubAccount.ps1 b/src/functions/public/Auth/Connect-GitHubAccount.ps1 index b2abd70af..c96affaa8 100644 --- a/src/functions/public/Auth/Connect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Connect-GitHubAccount.ps1 @@ -251,7 +251,7 @@ } $context += @{ PrivateKey = $PrivateKey - TokenType = 'PEM' + TokenType = 'JWT' ClientID = $ClientID } } diff --git a/src/functions/public/Auth/Connect-GitHubApp.ps1 b/src/functions/public/Auth/Connect-GitHubApp.ps1 index 0bb9a8012..e69343465 100644 --- a/src/functions/public/Auth/Connect-GitHubApp.ps1 +++ b/src/functions/public/Auth/Connect-GitHubApp.ps1 @@ -158,7 +158,7 @@ } Write-Verbose 'Logging in using a managed installation access token...' $contextParams | Format-Table | Out-String -Stream | ForEach-Object { Write-Verbose $_ } - $contextObj = [InstallationGitHubContext]::new((Set-GitHubContext -Context $contextParams.Clone() -PassThru -Default:$Default)) + $contextObj = [GitHubAppInstallationContext]::new((Set-GitHubContext -Context $contextParams.Clone() -PassThru -Default:$Default)) $contextObj | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ } if (-not $Silent) { $name = $contextObj.Name diff --git a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 index 4a9440ab3..083bf74ec 100644 --- a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 +++ b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 @@ -70,16 +70,16 @@ Write-Verbose 'Context:' $contextObj | Select-Object * | Out-String -Stream | ForEach-Object { Write-Verbose $_ } - Write-Verbose "Converting to: [$($contextObj.Type)GitHubContext]" + Write-Verbose "Converting to: [GitHub$($contextObj.Type)Context]" switch ($contextObj.Type) { 'User' { - [UserGitHubContext]::new([pscustomobject]$contextObj) + [GitHubUserContext]::new([pscustomobject]$contextObj) } 'App' { - [AppGitHubContext]::new([pscustomobject]$contextObj) + [GitHubAppContext]::new([pscustomobject]$contextObj) } 'Installation' { - [InstallationGitHubContext]::new([pscustomobject]$contextObj) + [GitHubAppInstallationContext]::new([pscustomobject]$contextObj) } default { throw "Unknown context type: [$($contextObj.Type)]" diff --git a/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 b/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 index 9a3878c56..aa27959e0 100644 --- a/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 @@ -64,7 +64,7 @@ Revoke-GitHubAppInstallationAccessToken -Context $contextItem } - Remove-GitHubContext -Context $contextItem + Remove-GitHubContext -Context $contextItem.ID $isDefaultContext = $contextItem.Name -eq $script:GitHub.Config.DefaultContext if ($isDefaultContext) { Remove-GitHubConfig -Name 'DefaultContext' diff --git a/src/types/GitHubContext.Types.ps1xml b/src/types/GitHubContext.Types.ps1xml index 0fde8366a..2e78158cb 100644 --- a/src/types/GitHubContext.Types.ps1xml +++ b/src/types/GitHubContext.Types.ps1xml @@ -1,7 +1,7 @@ - UserGitHubContext + GitHubUserContext TokenExpiresIn @@ -28,7 +28,7 @@ - InstallationGitHubContext + GitHubAppInstallationContext TokenExpiresIn diff --git a/src/types/GitHubEnvironment.Types.ps1xml b/src/types/GitHubEnvironment.Types.ps1xml index e058ce6f6..704e05b6d 100644 --- a/src/types/GitHubEnvironment.Types.ps1xml +++ b/src/types/GitHubEnvironment.Types.ps1xml @@ -3,10 +3,10 @@ GitHubEnvironment - + Environment - $this.Name - + Name + diff --git a/src/types/GitHubJsonWebToken.Types.ps1xml b/src/types/GitHubJsonWebToken.Types.ps1xml deleted file mode 100644 index da5897a60..000000000 --- a/src/types/GitHubJsonWebToken.Types.ps1xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - GitHubJsonWebToken - - - ExpiresIn - - if ($null -eq $this.ExpiresAt) { return } - $timeRemaining = $this.ExpiresAt - [DateTime]::Now - if ($timeRemaining.TotalSeconds -lt 0) { - return [TimeSpan]::Zero - } - return $timeRemaining - - - - - diff --git a/src/types/GitHubNode.Types.ps1xml b/src/types/GitHubNode.Types.ps1xml index 93f44daeb..11b5f73f6 100644 --- a/src/types/GitHubNode.Types.ps1xml +++ b/src/types/GitHubNode.Types.ps1xml @@ -3,10 +3,10 @@ GitHubNode - + DatabaseID - $this.ID - + ID + diff --git a/src/types/GitHubOrganization.Types.ps1xml b/src/types/GitHubOrganization.Types.ps1xml index 076d7b359..a793f8b4c 100644 --- a/src/types/GitHubOrganization.Types.ps1xml +++ b/src/types/GitHubOrganization.Types.ps1xml @@ -3,10 +3,10 @@ GitHubOrganization - + Organization - $this.Name - + Name + diff --git a/src/types/GitHubOwner.Types.ps1xml b/src/types/GitHubOwner.Types.ps1xml index 6fce86651..a6d41dd47 100644 --- a/src/types/GitHubOwner.Types.ps1xml +++ b/src/types/GitHubOwner.Types.ps1xml @@ -3,10 +3,10 @@ GitHubOwner - + Owner - $this.Name - + Name + diff --git a/src/types/GitHubRelease.Types.ps1xml b/src/types/GitHubRelease.Types.ps1xml index 1c1acc885..f1225bf33 100644 --- a/src/types/GitHubRelease.Types.ps1xml +++ b/src/types/GitHubRelease.Types.ps1xml @@ -3,10 +3,10 @@ GitHubRelease - + Release - $this.ID - + ID + diff --git a/src/types/GitHubRepository.Types.ps1xml b/src/types/GitHubRepository.Types.ps1xml index db9388f09..20ee8b423 100644 --- a/src/types/GitHubRepository.Types.ps1xml +++ b/src/types/GitHubRepository.Types.ps1xml @@ -3,10 +3,10 @@ GitHubRepository - + Repository - $this.Name - + Name + diff --git a/src/types/GitHubTeam.Types.ps1xml b/src/types/GitHubTeam.Types.ps1xml index 38abc2cc2..c5dc2c484 100644 --- a/src/types/GitHubTeam.Types.ps1xml +++ b/src/types/GitHubTeam.Types.ps1xml @@ -3,10 +3,10 @@ GitHubTeam - + Team - $this.Slug - + Slug + diff --git a/src/types/GitHubUser.Types.ps1xml b/src/types/GitHubUser.Types.ps1xml index 275d10688..ab12006c7 100644 --- a/src/types/GitHubUser.Types.ps1xml +++ b/src/types/GitHubUser.Types.ps1xml @@ -3,18 +3,18 @@ GitHubUser - + User - $this.Name - - + Name + + Bio - $this.Description - - + Description + + Blog - $this.Website - + Website + diff --git a/src/types/GitHubWorkflow.Types.ps1xml b/src/types/GitHubWorkflow.Types.ps1xml index cd6ddb51a..17f85b830 100644 --- a/src/types/GitHubWorkflow.Types.ps1xml +++ b/src/types/GitHubWorkflow.Types.ps1xml @@ -3,10 +3,10 @@ GitHubWorkflow - + Workflow - $this.ID - + ID + diff --git a/src/types/GitHubWorkflowRun.Types.ps1xml b/src/types/GitHubWorkflowRun.Types.ps1xml index 0a65f47a4..7d793df99 100644 --- a/src/types/GitHubWorkflowRun.Types.ps1xml +++ b/src/types/GitHubWorkflowRun.Types.ps1xml @@ -3,10 +3,10 @@ GitHubWorkflowRun - + WorkflowRun - $this.ID - + ID + diff --git a/tests/Apps.Tests.ps1 b/tests/Apps.Tests.ps1 index feb65b3d1..8904b0a8c 100644 --- a/tests/Apps.Tests.ps1 +++ b/tests/Apps.Tests.ps1 @@ -176,7 +176,7 @@ Describe 'Apps' { } It 'Connect-GitHubApp - Connects as a GitHub App to ' { - $context | Should -BeOfType 'InstallationGitHubContext' + $context | Should -BeOfType 'GitHubAppInstallationContext' $context.ClientID | Should -Be $githubApp.ClientID $context.TokenExpiresAt | Should -BeOfType [datetime] $context.InstallationID | Should -BeOfType [uint64] diff --git a/tests/Data/AuthCases.ps1 b/tests/Data/AuthCases.ps1 index f09e3ebaa..f01ec07da 100644 --- a/tests/Data/AuthCases.ps1 +++ b/tests/Data/AuthCases.ps1 @@ -51,7 +51,7 @@ @{ AuthType = 'App' Type = 'a GitHub App from an Organization' - Case = 'PEM + IAT' + Case = 'JWT + IAT' TokenType = 'APP_ORG' Target = 'organization account' Owner = 'psmodule-test-org' @@ -67,7 +67,7 @@ @{ AuthType = 'App' Type = 'a GitHub App from an Enterprise' - Case = 'PEM + IAT' + Case = 'JWT + IAT' TokenType = 'APP_ENT' Target = 'organization account' Owner = 'psmodule-test-org3' @@ -83,7 +83,7 @@ @{ AuthType = 'App' Type = 'a GitHub App from an Enterprise' - Case = 'PEM + IAT' + Case = 'JWT + IAT' TokenType = 'APP_ENT' Target = 'enterprise account' Owner = 'msx' From 09be1b5348446b2248e22050cacdb9b70cf8c0d1 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 17 Jul 2025 14:37:01 +0200 Subject: [PATCH 19/27] =?UTF-8?q?=F0=9F=9A=80=20[Feature]:=20Rename=20`Run?= =?UTF-8?q?StartedAt`=20attribute=20to=20`StartedAt`=20for=20workflow=20ru?= =?UTF-8?q?ns=20+=20example=20update=20(#480)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request refactors PowerShell scripts for managing GitHub apps and updates a property name in the `GitHubWorkflowRun` class for consistency. The changes focus on improving code clarity, standardizing naming conventions, and enhancing maintainability. ### 🌟 Updates to `GitHubWorkflowRun` class: * Renamed the `RunStartedAt` property to `StartedAt` for consistency with other properties. * Updated the constructor to reflect the property name change from `RunStartedAt` to `StartedAt`. ### Refactoring of GitHub app management scripts: * Removed the `examples/Apps/AppManagement.ps1` example entirely, consolidating its functionality into `examples/Apps/EnterpriseApps.ps1` for better organization. * Updated `examples/Apps/EnterpriseApps.ps1` to: - Replace hardcoded app IDs with a more flexible `$ClientIDs` array. - Introduce parameters for private key and client ID authentication (`$PrivateKey` and `$ClientID`). - Simplify organization filtering by using `$org.Name` instead of `$org.login`. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [x] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- examples/Apps/AppManagement.ps1 | 10 ---- examples/Apps/EnterpriseApps.ps1 | 53 +++++++------------ .../public/Workflows/GitHubWorkflowRun.ps1 | 4 +- 3 files changed, 20 insertions(+), 47 deletions(-) delete mode 100644 examples/Apps/AppManagement.ps1 diff --git a/examples/Apps/AppManagement.ps1 b/examples/Apps/AppManagement.ps1 deleted file mode 100644 index 677f9e0c3..000000000 --- a/examples/Apps/AppManagement.ps1 +++ /dev/null @@ -1,10 +0,0 @@ -# Install an app on the entire enterprise -$appIDs = @( - 'Iv1.f26b61bc99e69405' -) -$orgs = Get-GitHubOrganization -Enterprise 'msx' -foreach ($org in $orgs) { - foreach ($appID in $appIDs) { - Install-GitHubAppOnEnterpriseOrganization -Enterprise msx -Organization $org.login -ClientID $appID -RepositorySelection all - } -} diff --git a/examples/Apps/EnterpriseApps.ps1 b/examples/Apps/EnterpriseApps.ps1 index 2526b7b2d..eed2507df 100644 --- a/examples/Apps/EnterpriseApps.ps1 +++ b/examples/Apps/EnterpriseApps.ps1 @@ -1,40 +1,23 @@ -$appIDs = @( - 'qweqweqwe', - 'qweqweqweqwe' -) - -$organization = '*' -filter Install-GithubApp { - param( - [Parameter()] - [string] $Enterprise = 'msx', +$ClientID = '' +$PrivateKey = @' +-----BEGIN RSA PRIVATE KEY----- - [Parameter()] - [string] $Organization = '*', +-----END RSA PRIVATE KEY----- +'@ +Connect-GitHub -ClientID $ClientID -PrivateKey $PrivateKey +Connect-GitHubApp -Enterprise 'msx' - [Parameter( - Mandatory, - ValueFromPipeline - )] - [string] $AppID - ) +# The apps you want to install on orgs in the enterprise +$ClientIDs = @( + 'Iv1.f26b61bc99e69405' +) +$Enterprise = 'msx' +$Organization = '*' - process { - $installableOrgs = Get-GitHubOrganization -Enterprise $Enterprise - $orgs = $installableOrgs | Where-Object { $_.login -like $organization } - foreach ($org in $orgs) { - foreach ($appIDitem in $AppID) { - Install-GitHubApp -Enterprise $Enterprise -Organization $org.login -ClientID $appIDitem -RepositorySelection all | ForEach-Object { - [PSCustomObject]@{ - Organization = $org.login - AppID = $appIDitem - } - } - } - } +$installableOrgs = Get-GitHubOrganization -Enterprise $Enterprise +$orgs = $installableOrgs | Where-Object { $_.Name -like $Organization } +foreach ($org in $orgs) { + foreach ($ClientID in $ClientIDs) { + Install-GitHubApp -Enterprise $Enterprise -Organization $org.Name -ClientID $ClientID -RepositorySelection all } } - -$appIDs | Install-GitHubApp -Organization $organization - -$installation = Get-GitHubAppInstallation diff --git a/src/classes/public/Workflows/GitHubWorkflowRun.ps1 b/src/classes/public/Workflows/GitHubWorkflowRun.ps1 index 6a6e60e18..223434062 100644 --- a/src/classes/public/Workflows/GitHubWorkflowRun.ps1 +++ b/src/classes/public/Workflows/GitHubWorkflowRun.ps1 @@ -85,7 +85,7 @@ # The start time of the latest run. Resets on re-run. # Example: "2023-01-01T12:01:00Z" - [System.Nullable[datetime]] $RunStartedAt + [System.Nullable[datetime]] $StartedAt # The head commit details. # Example: (nullable-simple-commit object) @@ -126,7 +126,7 @@ $this.PullRequests = $_.pull_requests $this.CreatedAt = $_.created_at $this.UpdatedAt = $_.updated_at - $this.RunStartedAt = $_.run_started_at + $this.StartedAt = $_.run_started_at $this.Actor = [GitHubUser]::new($_.actor) $this.TriggeringActor = [GitHubUser]::new($_.triggering_actor) $this.HeadCommit = $_.head_commit From 465671b848af7d299501cbde04149dd3026667e4 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 18 Jul 2025 15:12:53 +0200 Subject: [PATCH 20/27] =?UTF-8?q?=F0=9F=9A=80=20[Feature]:=20Adding=20func?= =?UTF-8?q?tionality=20to=20sign=20JWTs=20via=20Key=20Vault=20Keys=20(#481?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces support for signing GitHub App JSON Web Tokens (JWTs) using Azure Key Vault in addition to local RSA private keys. It also refactors and enhances existing JWT-related functionality to improve maintainability and clarity. The most significant changes include the addition of Azure Key Vault integration, refactoring of JWT signing methods, and updates to related utility functions. - Fixes #470. ### Improvements to Authentication Logic * Enhanced `Connect-GitHubAccount` to support both private key and Azure Key Vault-based authentication for GitHub Apps, introducing new parameter sets and validation for `KeyVaultKeyReference`. ### Azure Key Vault Integration * Added a new `KeyVaultKeyReference` property to the `GitHubAppContext` class for specifying Azure Key Vault keys as an alternative to local private keys. * Introduced the `Add-GitHubKeyVaultJWTSignature` function to sign JWTs using Azure Key Vault keys, supporting both Azure CLI and Az PowerShell authentication. * Added utility functions `Test-GitHubAzureCLI` and `Test-GitHubAzPowerShell` to check for Azure CLI and Az PowerShell module installation and authentication. ### Refactoring of JWT Signing * Renamed `Add-GitHubJWTSignature` to `Add-GitHubLocalJWTSignature` for clarity and updated it to use the new `GitHubJWTComponent` helper for base64 URL encoding. * Updated `Update-GitHubAppJWT` to conditionally use either `Add-GitHubLocalJWTSignature` or `Add-GitHubKeyVaultJWTSignature` based on the presence of `PrivateKey` or `KeyVaultKeyReference` in the context. ### Enhancements to JWT Utility Functions * Added `GitHubJWTComponent` class to centralize base64 URL encoding logic and simplify JWT creation. * Updated `New-GitHubUnsignedJWT` to use `GitHubJWTComponent` for encoding JWT headers and payloads. ## See it in action https://github.com/PSModule/GitHub-Script/actions/runs/16364842244/job/46239654619 ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [x] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- README.md | 42 ++++++++ .../GitHubContext/GitHubAppContext.ps1 | 4 + src/classes/public/GitHubJWTComponent.ps1 | 15 +++ .../Add-GitHubKeyVaultJWTSignature.ps1 | 101 ++++++++++++++++++ ...re.ps1 => Add-GitHubLocalJWTSignature.ps1} | 29 ++--- .../GitHub Apps/New-GitHubUnsignedJWT.ps1 | 36 +++---- .../Test-GitHubJWTRefreshRequired.ps1 | 43 ++++++++ .../Apps/GitHub Apps/Update-GitHubAppJWT.ps1 | 92 +++++++++++++--- .../Auth/Context/Resolve-GitHubContext.ps1 | 3 +- .../Test-GitHubAccessTokenRefreshRequired.ps1 | 7 +- .../Update-GitHubUserAccessToken.ps1 | 12 +-- .../PowerShell/Test-GitHubAzPowerShell.ps1 | 66 ++++++++++++ .../PowerShell/Test-GitHubAzureCLI.ps1 | 65 +++++++++++ .../public/Auth/Connect-GitHubAccount.ps1 | 77 ++++++++----- src/variables/private/GitHub.ps1 | 2 +- tests/Apps.Tests.ps1 | 2 +- 16 files changed, 504 insertions(+), 92 deletions(-) create mode 100644 src/classes/public/GitHubJWTComponent.ps1 create mode 100644 src/functions/private/Apps/GitHub Apps/Add-GitHubKeyVaultJWTSignature.ps1 rename src/functions/private/Apps/GitHub Apps/{Add-GitHubJWTSignature.ps1 => Add-GitHubLocalJWTSignature.ps1} (64%) create mode 100644 src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 create mode 100644 src/functions/private/Utilities/PowerShell/Test-GitHubAzPowerShell.ps1 create mode 100644 src/functions/private/Utilities/PowerShell/Test-GitHubAzureCLI.ps1 diff --git a/README.md b/README.md index f8286fb13..583424976 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,48 @@ Connect-GitHubAccount -ClientID $ClientID -PrivateKey $PrivateKey Using this approach, the module will autogenerate a JWT every time you run a command. I.e. Get-GitHubApp. +#### Using a GitHub App with Azure Key Vault + +For enhanced security, you can store your GitHub App's keys in Azure Key Vault and use that as way to signing the JWTs. +This approach requires a pre-authenticated session with either Azure CLI or Azure PowerShell. + +**Prerequisites:** +- Azure CLI authenticated session (`az login`) or Azure PowerShell authenticated session (`Connect-AzAccount`) +- GitHub App private key stored as a key in Azure Key Vault, with 'Sign' as a permitted operation +- Appropriate permissions to read keys from the Key Vault, like 'Key Vault Crypto User' + +**Using Azure CLI authentication:** + +```powershell +# Ensure you're authenticated with Azure CLI +az login + +# Connect using Key Vault key reference (URI with or without version) +Connect-GitHubAccount -ClientID $ClientID -KeyVaultKeyReference 'https://my-keyvault.vault.azure.net/keys/github-app-private-key' +✓ Logged in as my-github-app! +``` + +**Using Azure PowerShell authentication:** + +```powershell +# Ensure you're authenticated with Azure PowerShell +Connect-AzAccount + +# Connect using Key Vault key reference (URI with or without version) +Connect-GitHubAccount -ClientID $ClientID -KeyVaultKeyReference 'https://my-keyvault.vault.azure.net/keys/github-app-private-key' +✓ Logged in as my-github-app! +``` + +**Using Key Vault key reference with version:** + +```powershell +# Connect using Key Vault key reference with specific version +Connect-GitHubAccount -ClientID $ClientID -KeyVaultKeyReference 'https://my-keyvault.vault.azure.net/keys/github-app-private-key/abc123def456' +✓ Logged in as my-github-app! +``` + +This method ensures that your private key is securely stored in Azure Key Vault and never exposed in your scripts or configuration files. + #### Using a different host If you are using GitHub Enterprise, you can use the `-Host` (or `-HostName`) parameter to specify the host you want to connect to. diff --git a/src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 b/src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 index 6f9995e5b..02cc68a67 100644 --- a/src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 +++ b/src/classes/public/Context/GitHubContext/GitHubAppContext.ps1 @@ -5,6 +5,9 @@ # The private key for the app. [securestring] $PrivateKey + # Azure Key Vault key reference for JWT signing (alternative to PrivateKey). + [string] $KeyVaultKeyReference + # Owner of the GitHub App [string] $OwnerName @@ -41,6 +44,7 @@ $this.PerPage = $Object.PerPage $this.ClientID = $Object.ClientID $this.PrivateKey = $Object.PrivateKey + $this.KeyVaultKeyReference = $Object.KeyVaultKeyReference $this.OwnerName = $Object.OwnerName $this.OwnerType = $Object.OwnerType $this.Permissions = $Object.Permissions diff --git a/src/classes/public/GitHubJWTComponent.ps1 b/src/classes/public/GitHubJWTComponent.ps1 new file mode 100644 index 000000000..2f24a1e55 --- /dev/null +++ b/src/classes/public/GitHubJWTComponent.ps1 @@ -0,0 +1,15 @@ +class GitHubJWTComponent { + static [string] ToBase64UrlString([hashtable] $Data) { + return [GitHubJWTComponent]::ConvertToBase64UrlFormat( + [System.Convert]::ToBase64String( + [System.Text.Encoding]::UTF8.GetBytes( + (ConvertTo-Json -InputObject $Data) + ) + ) + ) + } + + static [string] ConvertToBase64UrlFormat([string] $Base64String) { + return $Base64String.TrimEnd('=').Replace('+', '-').Replace('/', '_') + } +} diff --git a/src/functions/private/Apps/GitHub Apps/Add-GitHubKeyVaultJWTSignature.ps1 b/src/functions/private/Apps/GitHub Apps/Add-GitHubKeyVaultJWTSignature.ps1 new file mode 100644 index 000000000..1665a309c --- /dev/null +++ b/src/functions/private/Apps/GitHub Apps/Add-GitHubKeyVaultJWTSignature.ps1 @@ -0,0 +1,101 @@ +function Add-GitHubKeyVaultJWTSignature { + <# + .SYNOPSIS + Adds a JWT signature using Azure Key Vault. + + .DESCRIPTION + Signs an unsigned JWT (header.payload) using a key stored in Azure Key Vault. + The function supports authentication via Azure CLI or Az PowerShell module and returns the signed JWT as a secure string. + + .EXAMPLE + Add-GitHubKeyVaultJWTSignature -UnsignedJWT 'header.payload' -KeyVaultKeyReference 'https://myvault.vault.azure.net/keys/mykey' + + Output: + ```powershell + System.Security.SecureString + ``` + + Signs the provided JWT (`header.payload`) using the specified Azure Key Vault key, returning a secure string containing the signed JWT. + + .OUTPUTS + System.Security.SecureString + + .NOTES + The function returns a secure string containing the fully signed JWT (header.payload.signature). + Ensure Azure CLI or Az PowerShell is installed and authenticated before running this function. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'Used to handle secure string private keys.' + )] + [CmdletBinding()] + param ( + # The unsigned JWT (header.payload) to sign. + [Parameter(Mandatory)] + [string] $UnsignedJWT, + + # The Azure Key Vault key URL used for signing. + [Parameter(Mandatory)] + [string] $KeyVaultKeyReference + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + if (Test-GitHubAzureCLI) { + try { + $accessToken = (az account get-access-token --resource 'https://vault.azure.net/' --output json | ConvertFrom-Json).accessToken + } catch { + Write-Error "Failed to get access token from Azure CLI: $_" + return + } + } elseif (Test-GitHubAzPowerShell) { + try { + $accessToken = (Get-AzAccessToken -ResourceUrl 'https://vault.azure.net/').Token + } catch { + Write-Error "Failed to get access token from Az PowerShell: $_" + return + } + } else { + Write-Error 'Azure authentication is required. Please ensure you are logged in using either Azure CLI or Az PowerShell.' + return + } + + if ($accessToken -isnot [securestring]) { + $accessToken = ConvertTo-SecureString -String $accessToken -AsPlainText + } + + $hash64url = [GitHubJWTComponent]::ConvertToBase64UrlFormat( + [System.Convert]::ToBase64String( + [System.Security.Cryptography.SHA256]::Create().ComputeHash( + [System.Text.Encoding]::UTF8.GetBytes($UnsignedJWT) + ) + ) + ) + + $KeyVaultKeyReference = $KeyVaultKeyReference.TrimEnd('/') + + $params = @{ + Method = 'POST' + URI = "$KeyVaultKeyReference/sign?api-version=7.4" + Body = @{ + alg = 'RS256' + value = $hash64url + } | ConvertTo-Json + ContentType = 'application/json' + Authentication = 'Bearer' + Token = $accessToken + } + + $result = Invoke-RestMethod @params + $signature = $result.value + return (ConvertTo-SecureString -String "$UnsignedJWT.$signature" -AsPlainText) + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 b/src/functions/private/Apps/GitHub Apps/Add-GitHubLocalJWTSignature.ps1 similarity index 64% rename from src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 rename to src/functions/private/Apps/GitHub Apps/Add-GitHubLocalJWTSignature.ps1 index f00d160da..1c14e89f3 100644 --- a/src/functions/private/Apps/GitHub Apps/Add-GitHubJWTSignature.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Add-GitHubLocalJWTSignature.ps1 @@ -1,4 +1,4 @@ -function Add-GitHubJWTSignature { +function Add-GitHubLocalJWTSignature { <# .SYNOPSIS Signs a JSON Web Token (JWT) using a local RSA private key. @@ -8,26 +8,25 @@ function Add-GitHubJWTSignature { This function handles the RSA signing process and returns the complete signed JWT. .EXAMPLE - Add-GitHubJWTSignature -UnsignedJWT 'eyJ0eXAiOi...' -PrivateKey '--- BEGIN RSA PRIVATE KEY --- ... --- END RSA PRIVATE KEY ---' + Add-GitHubLocalJWTSignature -UnsignedJWT 'eyJ0eXAiOi...' -PrivateKey '--- BEGIN RSA PRIVATE KEY --- ... --- END RSA PRIVATE KEY ---' Adds a signature to the unsigned JWT using the provided private key. .OUTPUTS - String + securestring .NOTES This function isolates the signing logic to enable support for multiple signing methods. .LINK - https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Add-GitHubJWTSignature + https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Add-GitHubLocalJWTSignature #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( - 'PSAvoidUsingConvertToSecureStringWithPlainText', - '', + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'Used to handle secure string private keys.' )] [CmdletBinding()] - [OutputType([string])] + [OutputType([securestring])] param( # The unsigned JWT (header.payload) to sign. [Parameter(Mandatory)] @@ -52,14 +51,16 @@ function Add-GitHubJWTSignature { $rsa.ImportFromPem($PrivateKey) try { - $signature = [Convert]::ToBase64String( - $rsa.SignData( - [System.Text.Encoding]::UTF8.GetBytes($UnsignedJWT), - [System.Security.Cryptography.HashAlgorithmName]::SHA256, - [System.Security.Cryptography.RSASignaturePadding]::Pkcs1 + $signature = [GitHubJWTComponent]::ConvertToBase64UrlFormat( + [System.Convert]::ToBase64String( + $rsa.SignData( + [System.Text.Encoding]::UTF8.GetBytes($UnsignedJWT), + [System.Security.Cryptography.HashAlgorithmName]::SHA256, + [System.Security.Cryptography.RSASignaturePadding]::Pkcs1 + ) ) - ).TrimEnd('=').Replace('+', '-').Replace('/', '_') - return "$UnsignedJWT.$signature" + ) + return (ConvertTo-SecureString -String "$UnsignedJWT.$signature" -AsPlainText) } finally { if ($rsa) { $rsa.Dispose() diff --git a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 index 5332505c5..2d47a9f81 100644 --- a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 +++ b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 @@ -1,4 +1,4 @@ -function New-GitHubUnsignedJWT { +function New-GitHubUnsignedJWT { <# .SYNOPSIS Creates an unsigned JSON Web Token (JWT) for a GitHub App. @@ -38,30 +38,22 @@ function New-GitHubUnsignedJWT { } process { - $header = [Convert]::ToBase64String( - [System.Text.Encoding]::UTF8.GetBytes( - ( - ConvertTo-Json -InputObject @{ - alg = 'RS256' - typ = 'JWT' - } - ) - ) - ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + $header = [GitHubJWTComponent]::ToBase64UrlString( + @{ + alg = 'RS256' + typ = 'JWT' + } + ) $now = [System.DateTimeOffset]::UtcNow $iat = $now.AddSeconds(-$script:GitHub.Config.JwtTimeTolerance) $exp = $now.AddSeconds($script:GitHub.Config.JwtTimeTolerance) - $payload = [Convert]::ToBase64String( - [System.Text.Encoding]::UTF8.GetBytes( - ( - ConvertTo-Json -InputObject @{ - iat = $iat.ToUnixTimeSeconds() - exp = $exp.ToUnixTimeSeconds() - iss = $ClientID - } - ) - ) - ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + $payload = [GitHubJWTComponent]::ToBase64UrlString( + @{ + iat = $iat.ToUnixTimeSeconds() + exp = $exp.ToUnixTimeSeconds() + iss = $ClientID + } + ) [pscustomobject]@{ Base = "$header.$payload" IssuedAt = $iat.DateTime diff --git a/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 b/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 new file mode 100644 index 000000000..ae705ead3 --- /dev/null +++ b/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 @@ -0,0 +1,43 @@ +function Test-GitHubJWTRefreshRequired { + <# + .SYNOPSIS + Test if the GitHub JWT should be refreshed. + + .DESCRIPTION + Test if the GitHub JWT should be refreshed. JWTs are refreshed when they have 150 seconds or less remaining before expiration. + + .EXAMPLE + Test-GitHubJWTRefreshRequired -Context $Context + + This will test if the GitHub JWT should be refreshed for the specified context. + + .NOTES + JWTs are short-lived tokens (typically 10 minutes) and need to be refreshed more frequently than user access tokens. + The refresh threshold is set to 150 seconds (2.5 minutes) to ensure the JWT doesn't expire during API operations. + #> + [OutputType([bool])] + [CmdletBinding()] + param( + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + try { + ($Context.TokenExpiresAt - [datetime]::Now).TotalSeconds -le ($script:GitHub.Config.JwtTimeTolerance / 2) + } catch { + return $true + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 b/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 index de4ce05d4..350a47434 100644 --- a/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 @@ -4,15 +4,26 @@ Updates a JSON Web Token (JWT) for a GitHub App context. .DESCRIPTION - Updates a JSON Web Token (JWT) for a GitHub App context. + Updates a JSON Web Token (JWT) for a GitHub App context. If the JWT has half or less of its remaining duration before expiration, + it will be refreshed. This function implements mutex-based locking to prevent concurrent refreshes. .EXAMPLE Update-GitHubAppJWT -Context $Context Updates the JSON Web Token (JWT) for a GitHub App using the specified context. + .EXAMPLE + Update-GitHubAppJWT -Context $Context -PassThru + + This will update the GitHub App JWT for the specified context and return the updated context. + + .EXAMPLE + Update-GitHubAppJWT -Context $Context -Silent + + This will update the GitHub App JWT for the specified context without displaying progress messages. + .OUTPUTS - securestring + object .NOTES [Generating a JSON Web Token (JWT) for a GitHub App | GitHub Docs](https://docs.github.com/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-powershell-to-generate-a-jwt) @@ -20,6 +31,8 @@ .LINK https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Update-GitHubAppJWT #> + [CmdletBinding(SupportsShouldProcess)] + [OutputType([object])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidLongLines', '', Justification = 'Contains a long link.' @@ -28,12 +41,14 @@ 'PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'Generated JWT is a plaintext string.' )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Is the CLI part of the module.' + )] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Function creates a JWT without modifying system state' )] - [CmdletBinding()] - [OutputType([object])] param( # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. @@ -42,7 +57,11 @@ # Return the updated context. [Parameter()] - [switch] $PassThru + [switch] $PassThru, + + # Timeout in milliseconds for waiting on mutex. Default is 30 seconds. + [Parameter()] + [int] $TimeoutMs = 30000 ) begin { @@ -51,15 +70,64 @@ } process { - $unsignedJWT = New-GitHubUnsignedJWT -ClientId $Context.ClientID - $jwt = Add-GitHubJWTSignature -UnsignedJWT $unsignedJWT.Base -PrivateKey $Context.PrivateKey - $Context.Token = ConvertTo-SecureString -String $jwt -AsPlainText - $Context.TokenExpiresAt = $unsignedJWT.ExpiresAt - if ($Context.ID) { - $Context = Set-Context -Context $Context -Vault $script:GitHub.ContextVault -PassThru + if (Test-GitHubJWTRefreshRequired -Context $Context) { + $lockName = "PSModule.GitHub-$($Context.ID)".Replace('/', '-') + $lock = $null + try { + $lock = [System.Threading.Mutex]::new($false, $lockName) + $acquiredLock = $lock.WaitOne(0) + + if ($acquiredLock) { + try { + Write-Debug '⚠ JWT token nearing expiration. Refreshing JWT...' + $unsignedJWT = New-GitHubUnsignedJWT -ClientId $Context.ClientID + + if ($Context.KeyVaultKeyReference) { + Write-Debug "Using KeyVault Key Reference: $($Context.KeyVaultKeyReference)" + $Context.Token = Add-GitHubKeyVaultJWTSignature -UnsignedJWT $unsignedJWT.Base -KeyVaultKeyReference $Context.KeyVaultKeyReference + } elseif ($Context.PrivateKey) { + Write-Debug 'Using Private Key from context.' + $Context.Token = Add-GitHubLocalJWTSignature -UnsignedJWT $unsignedJWT.Base -PrivateKey $Context.PrivateKey + } else { + throw 'No Private Key or KeyVault Key Reference provided in the context.' + } + + $Context.TokenExpiresAt = $unsignedJWT.ExpiresAt + + if ($Context.ID) { + if ($PSCmdlet.ShouldProcess('JWT token', 'Update/refresh')) { + Set-Context -Context $Context -Vault $script:GitHub.ContextVault + } + } + } finally { + $lock.ReleaseMutex() + } + } else { + Write-Verbose "JWT token is being updated by another process. Waiting for mutex to be released (timeout: $($TimeoutMs)ms)..." + try { + if ($lock.WaitOne($TimeoutMs)) { + $Context = Resolve-GitHubContext -Context $Context.ID + $lock.ReleaseMutex() + } else { + Write-Warning 'Timeout waiting for JWT token update. Proceeding with current token state.' + } + } catch [System.Threading.AbandonedMutexException] { + Write-Debug 'Mutex was abandoned by another process. Re-checking JWT token state...' + $Context = Resolve-GitHubContext -Context $Context.ID + } + } + } finally { + if ($lock) { + $lock.Dispose() + } + } + } else { + # JWT is still valid, no refresh needed + Write-Debug 'JWT is still valid, no refresh needed' } + if ($PassThru) { - $Context + return $Context } } diff --git a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 index a089f6add..a28e871a6 100644 --- a/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Resolve-GitHubContext.ps1 @@ -41,7 +41,8 @@ } process { - Write-Verbose "Context: [$Context]" + Write-Verbose "Context:" + $Context | Out-String -Stream | ForEach-Object { Write-Verbose $_ } Write-Verbose "Anonymous: [$Anonymous]" if ($Anonymous -or $Context -eq 'Anonymous') { Write-Verbose 'Returning Anonymous context.' diff --git a/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 b/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 index d9320a85d..292ded46a 100644 --- a/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Test-GitHubAccessTokenRefreshRequired.ps1 @@ -26,8 +26,11 @@ } process { - $updateToken = ($Context.TokenExpiresAt - [datetime]::Now).TotalHours -lt $script:GitHub.Config.AccessTokenGracePeriodInHours - $updateToken + try { + ($Context.TokenExpiresAt - [datetime]::Now).TotalHours -lt $script:GitHub.Config.AccessTokenGracePeriodInHours + } catch { + return $true + } } end { diff --git a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 index 4f4ce2ffe..ab5183e7e 100644 --- a/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 +++ b/src/functions/private/Auth/DeviceFlow/Update-GitHubUserAccessToken.ps1 @@ -43,10 +43,6 @@ [Parameter()] [switch] $PassThru, - # Suppress output messages. - [Parameter()] - [switch] $Silent, - # Timeout in milliseconds for waiting on mutex. Default is 30 seconds. [Parameter()] [int] $TimeoutMs = 30000 @@ -55,12 +51,11 @@ begin { $stackPath = Get-PSCallStackPath Write-Debug "[$stackPath] - Start" - Assert-GitHubContext -Context $Context -AuthType UAT } process { if (Test-GitHubAccessTokenRefreshRequired -Context $Context) { - $lockName = "PSModule.GitHub/$($Context.ID)" + $lockName = "PSModule.GitHub-$($Context.ID)".Replace('/', '-') $lock = $null try { $lock = [System.Threading.Mutex]::new($false, $lockName) @@ -71,10 +66,7 @@ $refreshTokenValidity = [datetime]($Context.RefreshTokenExpiresAt) - [datetime]::Now $refreshTokenIsValid = $refreshTokenValidity.TotalSeconds -gt 0 if ($refreshTokenIsValid) { - if (-not $Silent) { - Write-Host '⚠ ' -ForegroundColor Yellow -NoNewline - Write-Host 'Access token expired. Refreshing access token...' - } + Write-Debug '⚠ Access token expired. Refreshing access token...' $tokenResponse = Invoke-GitHubDeviceFlowLogin -ClientID $Context.AuthClientID -RefreshToken $Context.RefreshToken -HostName $Context.HostName } else { Write-Verbose "Using $($Context.DeviceFlowType) authentication..." diff --git a/src/functions/private/Utilities/PowerShell/Test-GitHubAzPowerShell.ps1 b/src/functions/private/Utilities/PowerShell/Test-GitHubAzPowerShell.ps1 new file mode 100644 index 000000000..54aa9cf2c --- /dev/null +++ b/src/functions/private/Utilities/PowerShell/Test-GitHubAzPowerShell.ps1 @@ -0,0 +1,66 @@ +function Test-GitHubAzPowerShell { + <# + .SYNOPSIS + Tests if Azure PowerShell module is installed and authenticated. + + .DESCRIPTION + This function checks if the Azure PowerShell module (Az) is installed and the user is authenticated. + It verifies both the availability of the module and the authentication status. + + .EXAMPLE + Test-GitHubAzPowerShell + + Returns $true if Azure PowerShell module is installed and authenticated, $false otherwise. + + .OUTPUTS + [bool] + Returns $true if Azure PowerShell module is installed and authenticated, $false otherwise. + + .NOTES + This function is used internally by other GitHub module functions that require Azure PowerShell authentication, + such as Azure Key Vault operations for GitHub App JWT signing. + #> + [OutputType([bool])] + [CmdletBinding()] + param() + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + try { + # Check if Azure PowerShell module is installed + $azModule = Get-Module -Name 'Az.Accounts' -ListAvailable -ErrorAction SilentlyContinue + if (-not $azModule) { + Write-Debug "[$stackPath] - Azure PowerShell module (Az.Accounts) not found" + return $false + } + + # Check if the module is imported + $importedModule = Get-Module -Name 'Az.Accounts' -ErrorAction SilentlyContinue + if (-not $importedModule) { + Write-Debug "[$stackPath] - Attempting to import Az.Accounts module" + Import-Module -Name 'Az.Accounts' -ErrorAction SilentlyContinue + } + + # Check if user is authenticated by trying to get current context + $context = Get-AzContext -ErrorAction SilentlyContinue + if (-not $context -or [string]::IsNullOrEmpty($context.Account)) { + Write-Debug "[$stackPath] - Azure PowerShell authentication failed or no account logged in" + return $false + } + + Write-Debug "[$stackPath] - Azure PowerShell is installed and authenticated (Account: $($context.Account.Id))" + return $true + } catch { + Write-Debug "[$stackPath] - Error checking Azure PowerShell: $($_.Exception.Message)" + return $false + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Utilities/PowerShell/Test-GitHubAzureCLI.ps1 b/src/functions/private/Utilities/PowerShell/Test-GitHubAzureCLI.ps1 new file mode 100644 index 000000000..19a6db1f1 --- /dev/null +++ b/src/functions/private/Utilities/PowerShell/Test-GitHubAzureCLI.ps1 @@ -0,0 +1,65 @@ +function Test-GitHubAzureCLI { + <# + .SYNOPSIS + Tests if Azure CLI is installed and authenticated. + + .DESCRIPTION + This function checks if Azure CLI (az) is installed and the user is authenticated. + It verifies both the availability of the CLI tool and the authentication status. + + .EXAMPLE + Test-GitHubAzureCLI + + Returns $true if Azure CLI is installed and authenticated, $false otherwise. + + .OUTPUTS + bool + + .NOTES + This function is used internally by other GitHub module functions that require Azure CLI authentication, + such as Azure Key Vault operations for GitHub App JWT signing. + #> + [OutputType([bool])] + [CmdletBinding()] + param() + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + try { + # Check if Azure CLI is installed + $azCommand = Get-Command -Name 'az' -ErrorAction SilentlyContinue + if (-not $azCommand) { + Write-Debug "[$stackPath] - Azure CLI (az) command not found" + return $false + } + + # Check if user is authenticated by trying to get account info + $accountInfo = az account show --output json 2>$null + if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrEmpty($accountInfo)) { + Write-Debug "[$stackPath] - Azure CLI authentication failed or no account logged in" + return $false + } + + # Parse the account info to ensure it's valid + $account = $accountInfo | ConvertFrom-Json -ErrorAction SilentlyContinue + if (-not $account -or [string]::IsNullOrEmpty($account.id)) { + Write-Debug "[$stackPath] - Azure CLI account information is invalid" + return $false + } + + Write-Debug "[$stackPath] - Azure CLI is installed and authenticated (Account: $($account.id))" + return $true + } catch { + Write-Debug "[$stackPath] - Error checking Azure CLI: $($_.Exception.Message)" + return $false + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Auth/Connect-GitHubAccount.ps1 b/src/functions/public/Auth/Connect-GitHubAccount.ps1 index c96affaa8..20816ce7d 100644 --- a/src/functions/public/Auth/Connect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Connect-GitHubAccount.ps1 @@ -48,9 +48,18 @@ #> [Alias('Connect-GitHub')] [OutputType([void])] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Long links for documentation.')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Is the CLI part of the module.')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'The tokens are received as clear text. Mitigating exposure by removing variables and performing garbage collection.')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', '', + Justification = 'Long links for documentation.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Is the CLI part of the module.' + )] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'The tokens are received as clear text. Mitigating exposure by removing variables and performing garbage collection.' + )] [CmdletBinding(DefaultParameterSetName = 'UAT')] param( # Choose between authentication methods, either OAuthApp or GitHubApp. @@ -69,41 +78,39 @@ # The user will be prompted to enter the token. - [Parameter( - Mandatory, - ParameterSetName = 'PAT' - )] + [Parameter(Mandatory, ParameterSetName = 'PAT')] [switch] $UseAccessToken, # An access token to use for authentication. Can be both a string or a SecureString. # Supports both personal access tokens (PAT) and GitHub App installation access tokens (IAT). # Example: 'ghp_1234567890abcdef' # Example: 'ghs_1234567890abcdef' - [Parameter( - Mandatory, - ParameterSetName = 'Token' - )] + [Parameter(Mandatory, ParameterSetName = 'Token')] [object] $Token, # The client ID for the GitHub App to use for authentication. [Parameter(ParameterSetName = 'UAT')] - [Parameter( - Mandatory, - ParameterSetName = 'App' - )] + [Parameter(Mandatory, ParameterSetName = 'GitHub App using a PrivateKey')] + [Parameter(Mandatory, ParameterSetName = 'GitHub App using a KeyVault Key Reference')] [string] $ClientID, - # The private key for the GitHub App when authenticating as a GitHub App. - [Parameter( - Mandatory, - ParameterSetName = 'App' - )] + # The private key that is used to sign JWTs for the GitHub App. + [Parameter(Mandatory, ParameterSetName = 'GitHub App using a PrivateKey')] [object] $PrivateKey, + # The KeyVault Key Reference that can sign JWTs for the GitHub App. + [Parameter(Mandatory, ParameterSetName = 'GitHub App using a KeyVault Key Reference')] + [ValidateScript({ + if ($_ -notlike 'https://*.vault.azure.net/keys/*') { + throw "Invalid Key Vault key reference format: $_" + } + return $true + })] + [string] $KeyVaultKeyReference, + # Automatically load installations for the GitHub App. - [Parameter( - ParameterSetName = 'App' - )] + [Parameter(ParameterSetName = 'GitHub App using a PrivateKey')] + [Parameter(ParameterSetName = 'GitHub App using a KeyVault Key Reference')] [switch] $AutoloadInstallations, # The default enterprise to use in commands. @@ -160,10 +167,9 @@ $ApiVersion = $script:GitHub.Config.ApiVersion $HostName = $HostName -replace '^https?://' $ApiBaseUri = "https://api.$HostName" - $authType = $PSCmdlet.ParameterSetName # If running on GitHub Actions and no access token is provided, use the GitHub token. - if (($env:GITHUB_ACTIONS -eq 'true') -and $PSCmdlet.ParameterSetName -ne 'App') { + if ($script:IsGitHubActions -and $PSCmdlet.ParameterSetName -notin @('GitHub App using a PrivateKey', 'GitHub App using a KeyVault Key Reference')) { $customTokenProvided = -not [string]::IsNullOrEmpty($Token) $gitHubTokenPresent = Test-GitHubToken Write-Verbose "A token was provided: [$customTokenProvided]" @@ -181,7 +187,6 @@ HostName = [string]$HostName HttpVersion = [string]$httpVersion PerPage = [int]$perPage - AuthType = [string]$authType Enterprise = [string]$Enterprise Owner = [string]$Owner Repository = [string]$Repository @@ -189,7 +194,7 @@ $context | Format-Table | Out-String -Stream | ForEach-Object { Write-Verbose $_ } - switch ($authType) { + switch ($PSCmdlet.ParameterSetName) { 'UAT' { Write-Verbose 'Logging in using device flow...' if (-not [string]::IsNullOrEmpty($ClientID)) { @@ -218,6 +223,7 @@ switch ($Mode) { 'GitHubApp' { $context += @{ + AuthType = 'UAT' Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token TokenExpiresAt = ([DateTime]::Now).AddSeconds($tokenResponse.expires_in) TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern @@ -230,6 +236,7 @@ } 'OAuthApp' { $context += @{ + AuthType = 'UAT' Token = ConvertTo-SecureString -AsPlainText $tokenResponse.access_token TokenType = $tokenResponse.access_token -replace $script:GitHub.TokenPrefixPattern AuthClientID = $authClientID @@ -244,17 +251,27 @@ } } } - 'App' { - Write-Verbose 'Logging in as a GitHub App...' + 'GitHub App using a PrivateKey' { + Write-Verbose 'Logging in as a GitHub App using PrivateKey...' if (-not($PrivateKey -is [System.Security.SecureString])) { $PrivateKey = $PrivateKey | ConvertTo-SecureString -AsPlainText } $context += @{ + AuthType = 'APP' PrivateKey = $PrivateKey TokenType = 'JWT' ClientID = $ClientID } } + 'GitHub App using a KeyVault Key Reference' { + Write-Verbose 'Logging in as a GitHub App using KeyVault Key Reference...' + $context += @{ + AuthType = 'APP' + KeyVaultKeyReference = $KeyVaultKeyReference + TokenType = 'JWT' + ClientID = $ClientID + } + } 'PAT' { Write-Debug "UseAccessToken is set to [$UseAccessToken]. Using provided access token..." Write-Verbose 'Logging in using personal access token...' @@ -264,6 +281,7 @@ $Token = ConvertFrom-SecureString $accessTokenValue -AsPlainText $tokenType = $Token -replace $script:GitHub.TokenPrefixPattern $context += @{ + AuthType = 'PAT' Token = ConvertTo-SecureString -AsPlainText $Token TokenType = $tokenType } @@ -294,6 +312,7 @@ } } } + default {} } $contextObj = Set-GitHubContext -Context $context -Default:(!$NotDefault) -PassThru $contextObj | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ } diff --git a/src/variables/private/GitHub.ps1 b/src/variables/private/GitHub.ps1 index 883105756..93d1d1344 100644 --- a/src/variables/private/GitHub.ps1 +++ b/src/variables/private/GitHub.ps1 @@ -1,5 +1,5 @@ $script:IsGitHubActions = $env:GITHUB_ACTIONS -eq 'true' -$script:IsFunctionApp = -not [string]::IsNullOrEmpty($env:WEBSITE_PLATFORM_VERSION) +$script:IsFunctionApp = $env:FUNCTIONS_WORKER_RUNTIME -eq 'powershell' $script:IsLocal = -not ($script:IsGitHubActions -or $script:IsFunctionApp) $script:GitHub = [pscustomobject]@{ ContextVault = 'PSModule.GitHub' diff --git a/tests/Apps.Tests.ps1 b/tests/Apps.Tests.ps1 index 8904b0a8c..44803729b 100644 --- a/tests/Apps.Tests.ps1 +++ b/tests/Apps.Tests.ps1 @@ -24,8 +24,8 @@ Describe 'Apps' { Context 'As using on ' -ForEach $authCases { BeforeAll { - $context = Connect-GitHubAccount @connectParams -PassThru -Silent LogGroup 'Context' { + $context = Connect-GitHubAccount @connectParams -PassThru -Silent Write-Host ($context | Format-List | Out-String) } } From 6b2e03eff622a0a6ad0c116083892f7f7a7889e8 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 19 Jul 2025 00:01:39 +0200 Subject: [PATCH 21/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Enhance=20`Test?= =?UTF-8?q?-GitHubWebhookSignature`=20to=20support=20a=20full=20request=20?= =?UTF-8?q?object=20+=20`Context`=20bump=20(#482)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces several updates across multiple files, focusing on enhancing functionality, improving documentation, and updating dependencies. The most significant changes include updates to the `Test-GitHubWebhookSignature` function for better flexibility and security and the upgrade of required module versions. ### Functional Updates * `Test-GitHubWebhookSignature`: - Added support for validating webhook requests using the entire `Request` object, enabling automatic extraction of body and headers. - Updated descriptions to clarify the use of SHA-256 and added examples demonstrating validation with the `Request` object. ### Dependency Updates - Updated `#Requires` statements across multiple files to require version `8.1.1` of the `Context` module. The update fixes an issue where the GitHub module attempted to save a context with null values would throw a null-pointer exception. ### Test Enhancements - Expanded test coverage for `Test-GitHubWebhookSignature`, including scenarios for valid signatures, invalid signatures, and missing headers in the `Request` object. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- .github/PSModule.yml | 14 ++++ .../Auth/Context/Remove-GitHubContext.ps1 | 2 +- .../Auth/Context/Set-GitHubContext.ps1 | 2 +- .../Config/Initialize-GitHubConfig.ps1 | 2 +- .../public/Auth/Context/Get-GitHubContext.ps1 | 2 +- .../public/Config/Get-GitHubConfig.ps1 | 2 +- .../public/Config/Remove-GitHubConfig.ps1 | 2 +- .../public/Config/Set-GitHubConfig.ps1 | 2 +- .../Webhooks/Test-GitHubWebhookSignature.ps1 | 83 ++++++++++++++----- tests/GitHub.Tests.ps1 | 81 ++++++++++++------ 10 files changed, 140 insertions(+), 52 deletions(-) diff --git a/.github/PSModule.yml b/.github/PSModule.yml index 6d578178e..0e0770314 100644 --- a/.github/PSModule.yml +++ b/.github/PSModule.yml @@ -1,3 +1,17 @@ Test: CodeCoverage: PercentTarget: 50 +# TestResults: +# Skip: true +# SourceCode: +# Skip: true +# PSModule: +# Skip: true +# Module: +# Windows: +# Skip: true +# MacOS: +# Skip: true +# Build: +# Docs: +# Skip: true diff --git a/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 b/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 index 9b6f810d8..e74e8aa5d 100644 --- a/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 @@ -42,4 +42,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/private/Auth/Context/Set-GitHubContext.ps1 b/src/functions/private/Auth/Context/Set-GitHubContext.ps1 index 068bafa99..b38085248 100644 --- a/src/functions/private/Auth/Context/Set-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Set-GitHubContext.ps1 @@ -168,4 +168,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/private/Config/Initialize-GitHubConfig.ps1 b/src/functions/private/Config/Initialize-GitHubConfig.ps1 index 8c513a8f5..3ca1bc34d 100644 --- a/src/functions/private/Config/Initialize-GitHubConfig.ps1 +++ b/src/functions/private/Config/Initialize-GitHubConfig.ps1 @@ -75,4 +75,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 index 083bf74ec..ccdd620ae 100644 --- a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 +++ b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 @@ -92,4 +92,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/public/Config/Get-GitHubConfig.ps1 b/src/functions/public/Config/Get-GitHubConfig.ps1 index 9a2a30922..e8a0ee1bc 100644 --- a/src/functions/public/Config/Get-GitHubConfig.ps1 +++ b/src/functions/public/Config/Get-GitHubConfig.ps1 @@ -47,4 +47,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/public/Config/Remove-GitHubConfig.ps1 b/src/functions/public/Config/Remove-GitHubConfig.ps1 index 148e3f264..e432b7044 100644 --- a/src/functions/public/Config/Remove-GitHubConfig.ps1 +++ b/src/functions/public/Config/Remove-GitHubConfig.ps1 @@ -44,4 +44,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/public/Config/Set-GitHubConfig.ps1 b/src/functions/public/Config/Set-GitHubConfig.ps1 index 029b5640b..e70f260ce 100644 --- a/src/functions/public/Config/Set-GitHubConfig.ps1 +++ b/src/functions/public/Config/Set-GitHubConfig.ps1 @@ -54,4 +54,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.0' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } diff --git a/src/functions/public/Webhooks/Test-GitHubWebhookSignature.ps1 b/src/functions/public/Webhooks/Test-GitHubWebhookSignature.ps1 index 71b040663..a7e53b49a 100644 --- a/src/functions/public/Webhooks/Test-GitHubWebhookSignature.ps1 +++ b/src/functions/public/Webhooks/Test-GitHubWebhookSignature.ps1 @@ -5,9 +5,9 @@ .DESCRIPTION This function validates the integrity and authenticity of a GitHub webhook request by comparing - the received HMAC SHA-256 signature against a computed hash of the payload using a shared secret. - It uses a constant-time comparison to mitigate timing attacks and returns a boolean indicating - whether the signature is valid. + the received HMAC signature against a computed hash of the payload using a shared secret. + It uses the SHA-256 algorithm and employs a constant-time comparison to mitigate + timing attacks. The function returns a boolean indicating whether the signature is valid. .EXAMPLE Test-GitHubWebhookSignature -Secret $env:WEBHOOK_SECRET -Body $Request.RawBody -Signature $Request.Headers['X-Hub-Signature-256'] @@ -19,6 +19,16 @@ Validates the provided webhook payload against the HMAC SHA-256 signature using the given secret. + .EXAMPLE + Test-GitHubWebhookSignature -Secret $env:WEBHOOK_SECRET -Request $Request + + Output: + ```powershell + True + ``` + + Validates the webhook request using the entire request object, automatically extracting the body and signature. + .OUTPUTS bool @@ -29,11 +39,12 @@ .LINK https://psmodule.io/GitHub/Functions/Webhooks/Test-GitHubWebhookSignature - .LINK - https://docs.github.com/webhooks/using-webhooks/validating-webhook-deliveries + .NOTES + [Validating Webhook Deliveries | GitHub Docs](https://docs.github.com/webhooks/using-webhooks/validating-webhook-deliveries) + [Webhook events and payloads | GitHub Docs](https://docs.github.com/en/webhooks/webhook-events-and-payloads) #> [OutputType([bool])] - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'ByBody')] param ( # The secret key used to compute the HMAC hash. # Example: 'mysecret' @@ -43,25 +54,59 @@ # The JSON body of the GitHub webhook request. # This must be the compressed JSON payload received from GitHub. # Example: '{"action":"opened"}' - [Parameter(Mandatory)] + [Parameter(Mandatory, ParameterSetName = 'ByBody')] [string] $Body, # The signature received from GitHub to compare against. # Example: 'sha256=abc123...' - [Parameter(Mandatory)] - [string] $Signature + [Parameter(Mandatory, ParameterSetName = 'ByBody')] + [string] $Signature, + + # The entire request object containing RawBody and Headers. + # Used in Azure Function Apps or similar environments. + [Parameter(Mandatory, ParameterSetName = 'ByRequest')] + [PSObject] $Request ) - $keyBytes = [Text.Encoding]::UTF8.GetBytes($Secret) - $payloadBytes = [Text.Encoding]::UTF8.GetBytes($Body) + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } - $hmac = [System.Security.Cryptography.HMACSHA256]::new() - $hmac.Key = $keyBytes - $hashBytes = $hmac.ComputeHash($payloadBytes) - $computedSignature = 'sha256=' + (($hashBytes | ForEach-Object { $_.ToString('x2') }) -join '') + process { + # Handle parameter sets + if ($PSCmdlet.ParameterSetName -eq 'ByRequest') { + $Body = $Request.RawBody + $Signature = $Request.Headers['X-Hub-Signature-256'] - [System.Security.Cryptography.CryptographicOperations]::FixedTimeEquals( - [Text.Encoding]::UTF8.GetBytes($computedSignature), - [Text.Encoding]::UTF8.GetBytes($Signature) - ) + # If signature not found, throw an error + if (-not $Signature) { + throw "No webhook signature found in request headers. Expected 'X-Hub-Signature-256' for SHA256 algorithm." + } + } + + $keyBytes = [Text.Encoding]::UTF8.GetBytes($Secret) + $payloadBytes = [Text.Encoding]::UTF8.GetBytes($Body) + + # Create HMAC SHA256 object + $hmac = [System.Security.Cryptography.HMACSHA256]::new() + $algorithmPrefix = 'sha256=' + + $hmac.Key = $keyBytes + $hashBytes = $hmac.ComputeHash($payloadBytes) + $computedSignature = $algorithmPrefix + (($hashBytes | ForEach-Object { $_.ToString('x2') }) -join '') + + # Dispose of the HMAC object + $hmac.Dispose() + + [System.Security.Cryptography.CryptographicOperations]::FixedTimeEquals( + [Text.Encoding]::UTF8.GetBytes($computedSignature), + [Text.Encoding]::UTF8.GetBytes($Signature) + ) + } + + end { + Write-Debug "[$stackPath] - End" + } } + diff --git a/tests/GitHub.Tests.ps1 b/tests/GitHub.Tests.ps1 index 474160fbf..988d7a891 100644 --- a/tests/GitHub.Tests.ps1 +++ b/tests/GitHub.Tests.ps1 @@ -179,6 +179,37 @@ Describe 'Auth' { } } +Describe 'Anonymous - Functions that can run anonymously' { + It 'Get-GithubRateLimit - Using -Anonymous' { + $rateLimit = Get-GitHubRateLimit -Anonymous + LogGroup 'Rate Limit' { + Write-Host ($rateLimit | Format-Table | Out-String) + } + $rateLimit | Should -Not -BeNullOrEmpty + } + It 'Invoke-GitHubAPI - Using -Anonymous' { + $rateLimit = Invoke-GitHubAPI -ApiEndpoint '/rate_limit' -Anonymous | Select-Object -ExpandProperty Response + LogGroup 'Rate Limit' { + Write-Host ($rateLimit | Format-Table | Out-String) + } + $rateLimit | Should -Not -BeNullOrEmpty + } + It 'Get-GithubRateLimit - Using -Context Anonymous' { + $rateLimit = Get-GitHubRateLimit -Context Anonymous + LogGroup 'Rate Limit' { + Write-Host ($rateLimit | Format-List | Out-String) + } + $rateLimit | Should -Not -BeNullOrEmpty + } + It 'Invoke-GitHubAPI - Using -Context Anonymous' { + $rateLimit = Invoke-GitHubAPI -ApiEndpoint '/rate_limit' -Context Anonymous | Select-Object -ExpandProperty Response + LogGroup 'Rate Limit' { + Write-Host ($rateLimit | Format-Table | Out-String) + } + $rateLimit | Should -Not -BeNullOrEmpty + } +} + Describe 'GitHub' { Context 'Config' { It 'Get-GitHubConfig - Gets the module configuration' { @@ -780,42 +811,40 @@ Describe 'Emojis' { } Describe 'Webhooks' { - It 'Test-GitHubWebhookSignature - Validates the webhook payload using known correct signature' { + BeforeAll { $secret = "It's a Secret to Everybody" $payload = 'Hello, World!' $signature = 'sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17' + } + + It 'Test-GitHubWebhookSignature - Validates the webhook payload using known correct signature (SHA256)' { $result = Test-GitHubWebhookSignature -Secret $secret -Body $payload -Signature $signature $result | Should -Be $true } -} -Describe 'Anonymous - Functions that can run anonymously' { - It 'Get-GithubRateLimit - Using -Anonymous' { - $rateLimit = Get-GitHubRateLimit -Anonymous - LogGroup 'Rate Limit' { - Write-Host ($rateLimit | Format-Table | Out-String) - } - $rateLimit | Should -Not -BeNullOrEmpty - } - It 'Invoke-GitHubAPI - Using -Anonymous' { - $rateLimit = Invoke-GitHubAPI -ApiEndpoint '/rate_limit' -Anonymous | Select-Object -ExpandProperty Response - LogGroup 'Rate Limit' { - Write-Host ($rateLimit | Format-Table | Out-String) + It 'Test-GitHubWebhookSignature - Validates the webhook using Request object' { + $mockRequest = [PSCustomObject]@{ + RawBody = $payload + Headers = @{ + 'X-Hub-Signature-256' = $signature + } } - $rateLimit | Should -Not -BeNullOrEmpty + $result = Test-GitHubWebhookSignature -Secret $secret -Request $mockRequest + $result | Should -Be $true } - It 'Get-GithubRateLimit - Using -Context Anonymous' { - $rateLimit = Get-GitHubRateLimit -Context Anonymous - LogGroup 'Rate Limit' { - Write-Host ($rateLimit | Format-List | Out-String) - } - $rateLimit | Should -Not -BeNullOrEmpty + + It 'Test-GitHubWebhookSignature - Should fail with invalid signature' { + $invalidSignature = 'sha256=invalid' + $result = Test-GitHubWebhookSignature -Secret $secret -Body $payload -Signature $invalidSignature + $result | Should -Be $false } - It 'Invoke-GitHubAPI - Using -Context Anonymous' { - $rateLimit = Invoke-GitHubAPI -ApiEndpoint '/rate_limit' -Context Anonymous | Select-Object -ExpandProperty Response - LogGroup 'Rate Limit' { - Write-Host ($rateLimit | Format-Table | Out-String) + + It 'Test-GitHubWebhookSignature - Should throw when signature header is missing from request' { + $mockRequest = [PSCustomObject]@{ + RawBody = $payload + Headers = @{} } - $rateLimit | Should -Not -BeNullOrEmpty + + { Test-GitHubWebhookSignature -Secret $secret -Request $mockRequest } | Should -Throw } } From 2dff5b76cd2a89d4f35c6582fbeb9a8ea2854f47 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 6 Aug 2025 12:33:35 +0200 Subject: [PATCH 22/27] =?UTF-8?q?=F0=9F=AA=B2=20[Fix]:=20Skip=20revoke=20t?= =?UTF-8?q?oken=20if=20token=20is=20expired=20(#488)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request refactors the conditional logic in the `Disconnect-GitHubAccount` function to improve readability and debugging and that actually skips the revocation of the token if it is expired. Refactoring and debugging improvements: * Added a condition to check if the token is expired before running the `Revoke-GitHubAppInstallationAccessToken`. The issue here was that the function would fail if it was expired. * Split the previous compound conditional into three distinct variables: `$isNotGitHubToken`, `$isIATAuthType`, and `$isNotExpired` for clarity and maintainability. * Added `Write-Debug` statements for each condition to facilitate easier troubleshooting and understanding of the script's flow. ## Type of change - [ ] 📖 [Docs] - [x] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- src/functions/public/Auth/Disconnect-GitHubAccount.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 b/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 index aa27959e0..0007e1958 100644 --- a/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 +++ b/src/functions/public/Auth/Disconnect-GitHubAccount.ps1 @@ -59,8 +59,13 @@ $contextItem = Resolve-GitHubContext -Context $contextItem $contextToken = Get-GitHubAccessToken -Context $contextItem -AsPlainText - $isGitHubToken = $contextToken -eq (Get-GitHubToken | ConvertFrom-SecureString -AsPlainText) - if (-not $isGitHubToken -and $contextItem.AuthType -eq 'IAT') { + $isNotGitHubToken = -not ($contextToken -eq (Get-GitHubToken | ConvertFrom-SecureString -AsPlainText)) + $isIATAuthType = $contextItem.AuthType -eq 'IAT' + $isNotExpired = $contextItem.TokenExpiresIn -gt 0 + Write-Debug "isNotGitHubToken: $isNotGitHubToken" + Write-Debug "isIATAuthType: $isIATAuthType" + Write-Debug "isNotExpired: $isNotExpired" + if ($isNotGitHubToken -and $isIATAuthType -and $isNotExpired) { Revoke-GitHubAppInstallationAccessToken -Context $contextItem } From 036e74a72f583d4a135558175f73a9d659002baa Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 6 Aug 2025 23:28:12 +0200 Subject: [PATCH 23/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Update=20the=20?= =?UTF-8?q?examples=20for=20how=20to=20connect=20using=20the=20module=20(#?= =?UTF-8?q?489)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request updates the `examples/Connecting.ps1` script to clarify and expand the usage examples for GitHub connection methods, including new authentication flows and improved documentation. The changes also make some minor corrections to comments and example commands related to context management. Authentication and connection improvements: * Added examples for connecting to GitHub programmatically using a token and clarified support for both fine-grained and classic PATs in the `Connect-GitHub` command. * Added new examples for connecting using a GitHub App with a private key stored in Azure Key Vault, including the use of `Connect-GitHubApp` for organizational contexts. * Improved comments for OAuth App, Device Flow, and PAT authentication flows to clarify best practices and supported scenarios. Context and profile management: * Updated comments to clarify that context names can be tab-completed and corrected a typo in the `Switch-GitHubContext` example (`Switch-GitHubCwontext`). ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- examples/Connecting.ps1 | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/Connecting.ps1 b/examples/Connecting.ps1 index 810b6d05a..005786ce0 100644 --- a/examples/Connecting.ps1 +++ b/examples/Connecting.ps1 @@ -7,22 +7,30 @@ Connect-GitHub # Log on to a specific instance of GitHub (enterprise) Connect-GitHub -Host 'msx.ghe.com' -Get-GitHubRepository -Context 'msx.ghe.com/MariusStorhaug' # Contexts should be selectable/overrideable on any call +Get-GitHubRepository -Context 'msx.ghe.com/MariusStorhaug' # Contexts are selectable/overrideable on any call -# Connect to GitHub interactively using OAuth App and Device Flow (should not use this, should we even support it?) +# Connect to GitHub interactively using OAuth App and Device Flow. Connect-GitHub -Mode 'OAuthApp' -Scope 'gist read:org repo workflow' -# Connect to GitHub interactively using less desired PAT flow +# Connect to GitHub interactively using less desired PAT flow, supports both fine-grained and classic PATs Connect-GitHub -UseAccessToken +# Connect to GitHub programatically (GitHub App Installation Access Token or PAT) +Connect-GitHub -Token *********** + # Connect to GitHub programatically (GitHub Actions) Connect-GitHub # Looks for the GITHUB_TOKEN variable -# Connect to GitHub programatically (GitHub App, for GitHub Actions or external applications, JWT login) +# Connect using a GitHub App and its private key (local signing of JWT) Connect-GitHub -ClientID '' -PrivateKey '' -# Connect to GitHub programatically (GitHub App Installation Access Token or PAT) -Connect-GitHub -Token *********** +# Connect using a GitHub App and the Key vault for signing the JWT. +# Prereq: The private key is stored in an Azure Key Vault and the shell has an authenticated Azure PowerShell or Azure CLI session +$ClientID = 'Iv23lieHcDQDwVV3alK1' +$KeyVaultKeyReference = 'https://psmodule-test-vault.vault.azure.net/keys/psmodule-ent-app' +Connect-GitHub -ClientID $ClientID -KeyVaultKeyReference $KeyVaultKeyReference +Connect-GitHubApp -Organization 'dnb-tooling' + ### ### Contexts / Profiles @@ -37,14 +45,12 @@ Get-GitHubContext -ListAvailable # Returns a specific context, autocomplete the name. Get-GitHubContext -Context 'msx.ghe.com/MariusStorhaug' -# Take a name dynamically from Get-GitHubContext? Autocomplete the name +# Take a name dynamically from Get-GitHubContext? tab-complete the name Switch-GitHubContext -Context 'msx.ghe.com/MariusStorhaug' # Set a specific context as the default context using pipeline 'msx.ghe.com/MariusStorhaug' | Switch-GitHubContext -Get-GitHubContext -Context 'github.com/MariusStorhaug' | Switch-GitHubContext - # Abstraction layers on GitHubContexts Get-GitHubContext -Context 'msx.ghe.com/MariusStorhaug' From 9550a2986a53e89152dda80ffff89a67c40317fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 08:29:49 +0200 Subject: [PATCH 24/27] Bump actions/checkout from 4 to 5 (#490) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
Release notes

Sourced from actions/checkout's releases.

v5.0.0

What's Changed

⚠️ Minimum Compatible Runner Version

v2.327.1
Release Notes

Make sure your runner is updated to this version or newer to use this release.

Full Changelog: https://github.com/actions/checkout/compare/v4...v5.0.0

v4.3.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4...v4.3.0

v4.2.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.2.1...v4.2.2

v4.2.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.2.0...v4.2.1

... (truncated)

Changelog

Sourced from actions/checkout's changelog.

Changelog

V5.0.0

V4.3.0

v4.2.2

v4.2.1

v4.2.0

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/Linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Linter.yml b/.github/workflows/Linter.yml index 6c163eb41..8017f6334 100644 --- a/.github/workflows/Linter.yml +++ b/.github/workflows/Linter.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 From 05728fd3b4eab9da99de3e0308cc540c88c67715 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 1 Sep 2025 14:33:36 +0200 Subject: [PATCH 25/27] =?UTF-8?q?=F0=9F=A9=B9=20Add=20support=20for=20Linu?= =?UTF-8?q?x=20ARM64=20(#492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request updates the required module versions for the `Context` and `Sodium` modules across both private and public function. Module version updates: * Updated the required version of the `Context` module from `8.1.1` to `8.1.3` in all relevant scripts, including `Remove-GitHubContext.ps1`, `Set-GitHubContext.ps1`, `Initialize-GitHubConfig.ps1`, `Get-GitHubContext.ps1`, `Get-GitHubConfig.ps1`, `Remove-GitHubConfig.ps1`, and `Set-GitHubConfig.ps1`. * Updated the required version of the `Sodium` module from `2.2.0` to `2.2.2` in `Set-GitHubSecret.ps1`. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> Co-authored-by: Marius Storhaug --- .../Auth/Context/Remove-GitHubContext.ps1 | 2 +- .../private/Auth/Context/Set-GitHubContext.ps1 | 3 ++- .../private/Config/Initialize-GitHubConfig.ps1 | 3 ++- .../public/Auth/Context/Get-GitHubContext.ps1 | 3 ++- .../public/Config/Get-GitHubConfig.ps1 | 3 ++- .../public/Config/Remove-GitHubConfig.ps1 | 3 ++- .../public/Config/Set-GitHubConfig.ps1 | 3 ++- .../public/Secrets/Set-GitHubSecret.ps1 | 2 +- tests/Secrets.Tests.ps1 | 18 +++++++----------- 9 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 b/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 index e74e8aa5d..6186b4807 100644 --- a/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Remove-GitHubContext.ps1 @@ -42,4 +42,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } diff --git a/src/functions/private/Auth/Context/Set-GitHubContext.ps1 b/src/functions/private/Auth/Context/Set-GitHubContext.ps1 index b38085248..c20ea4281 100644 --- a/src/functions/private/Auth/Context/Set-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Set-GitHubContext.ps1 @@ -168,4 +168,5 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } + diff --git a/src/functions/private/Config/Initialize-GitHubConfig.ps1 b/src/functions/private/Config/Initialize-GitHubConfig.ps1 index 3ca1bc34d..651445856 100644 --- a/src/functions/private/Config/Initialize-GitHubConfig.ps1 +++ b/src/functions/private/Config/Initialize-GitHubConfig.ps1 @@ -75,4 +75,5 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } + diff --git a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 index ccdd620ae..9f0015551 100644 --- a/src/functions/public/Auth/Context/Get-GitHubContext.ps1 +++ b/src/functions/public/Auth/Context/Get-GitHubContext.ps1 @@ -92,4 +92,5 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } + diff --git a/src/functions/public/Config/Get-GitHubConfig.ps1 b/src/functions/public/Config/Get-GitHubConfig.ps1 index e8a0ee1bc..9471de437 100644 --- a/src/functions/public/Config/Get-GitHubConfig.ps1 +++ b/src/functions/public/Config/Get-GitHubConfig.ps1 @@ -47,4 +47,5 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } + diff --git a/src/functions/public/Config/Remove-GitHubConfig.ps1 b/src/functions/public/Config/Remove-GitHubConfig.ps1 index e432b7044..8ae72d979 100644 --- a/src/functions/public/Config/Remove-GitHubConfig.ps1 +++ b/src/functions/public/Config/Remove-GitHubConfig.ps1 @@ -44,4 +44,5 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } + diff --git a/src/functions/public/Config/Set-GitHubConfig.ps1 b/src/functions/public/Config/Set-GitHubConfig.ps1 index e70f260ce..648ab97a7 100644 --- a/src/functions/public/Config/Set-GitHubConfig.ps1 +++ b/src/functions/public/Config/Set-GitHubConfig.ps1 @@ -54,4 +54,5 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.1' } +#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '8.1.3' } + diff --git a/src/functions/public/Secrets/Set-GitHubSecret.ps1 b/src/functions/public/Secrets/Set-GitHubSecret.ps1 index a92474e0e..c1da2a007 100644 --- a/src/functions/public/Secrets/Set-GitHubSecret.ps1 +++ b/src/functions/public/Secrets/Set-GitHubSecret.ps1 @@ -143,4 +143,4 @@ Write-Debug "[$stackPath] - End" } } -#Requires -Modules @{ ModuleName = 'Sodium'; RequiredVersion = '2.2.0'} +#Requires -Modules @{ ModuleName = 'Sodium'; RequiredVersion = '2.2.2'} diff --git a/tests/Secrets.Tests.ps1 b/tests/Secrets.Tests.ps1 index 2384187ab..48bff8af7 100644 --- a/tests/Secrets.Tests.ps1 +++ b/tests/Secrets.Tests.ps1 @@ -129,6 +129,7 @@ Describe 'Secrets' { Write-Host ($org | Format-List | Out-String) } } + Context 'PublicKey' { It 'Get-GitHubPublicKey - Action' { $result = Get-GitHubPublicKey @scope @@ -139,18 +140,13 @@ Describe 'Secrets' { } It 'Get-GitHubPublicKey - Codespaces' { - switch ($org.plan.name) { - 'free' { - { Get-GitHubPublicKey @scope -Type codespaces } | Should -Throw - } - default { - $result = Get-GitHubPublicKey @scope -Type codespaces - LogGroup 'PublicKey' { - Write-Host "$($result | Select-Object * | Format-Table -AutoSize | Out-String)" - } - $result | Should -Not -BeNullOrEmpty - } + $plan = $org.plan.name + Write-Host "Running with plan [$plan]" + $result = Get-GitHubPublicKey @scope -Type codespaces + LogGroup 'PublicKey' { + Write-Host "$($result | Select-Object * | Format-Table -AutoSize | Out-String)" } + $result | Should -Not -BeNullOrEmpty } } From 82939b5cb2146f7eba6c546e421505722a75ae86 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 4 Sep 2025 12:39:31 +0200 Subject: [PATCH 26/27] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20`TokenExp?= =?UTF-8?q?iresAt`=20property=20and=20update=20expiration=20logic=20for=20?= =?UTF-8?q?GitHubAppContext=20(#494)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request improves how token expiry information is handled and displayed for GitHub authentication contexts in both code and documentation. The main changes introduce automatic token renewal for GitHub Apps, add new properties to track token expiry, update formatting and type definitions to support these properties, and enhance tests to validate the new behavior. **Authentication and token management improvements:** * Added documentation in `README.md` explaining that short-lived tokens (for GitHub Apps) are automatically renewed by the module, clarifying the difference from long-lived tokens. * Removed outdated/duplicated token renewal documentation and examples from `README.md` to streamline the explanation. **Code and formatting updates:** * Added `TokenExpiresAt` property to `GitHubContext` and `GitHubAppContext` classes, and implemented a `TokenExpiresIn` script property for `GitHubAppContext` to calculate remaining token time. * Updated `GitHubContext.Format.ps1xml` to display `TokenExpiresAt` and `TokenExpiresIn` in relevant views, adjusted expiry logic (`-le 0` instead of `-lt 0`), and added special handling for token types (e.g., 10-minute expiry for APP tokens). **Testing enhancements:** * Extended tests in `GitHub.Tests.ps1` to verify that authentication contexts include valid `TokenExpiresAt` and `TokenExpiresIn` properties. ## Type of change - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> --- README.md | 36 +++------- src/classes/public/Config/GitHubConfig.ps1 | 3 - src/classes/public/Context/GitHubContext.ps1 | 1 + src/formats/GitHubConfig.Format.ps1xml | 3 - src/formats/GitHubContext.Format.ps1xml | 35 ++++++---- .../GitHub Apps/New-GitHubUnsignedJWT.ps1 | 4 +- .../Test-GitHubJWTRefreshRequired.ps1 | 2 +- src/types/GitHubContext.Types.ps1xml | 20 +++++- src/variables/private/GitHub.ps1 | 1 - tests/Emojis.Tests.ps1 | 67 +++++++++++++++++++ tests/GitHub.Tests.ps1 | 52 ++------------ 11 files changed, 125 insertions(+), 99 deletions(-) create mode 100644 tests/Emojis.Tests.ps1 diff --git a/README.md b/README.md index 583424976..c84fbb0f4 100644 --- a/README.md +++ b/README.md @@ -70,34 +70,7 @@ Press Enter to open github.com in your browser...: #-> Press enter and paste th After this you will need to install the GitHub App on the repos you want to manage. You can do this by visiting the [PowerShell for GitHub](https://github.com/apps/powershell-for-github) app page. -> Info: We will be looking to include this as a check in the module in the future. So it becomes a part of the regular sign in process. -Consecutive runs of the `Connect-GitHubAccount` will not require you to paste the code again unless you revoke the token -or you change the type of authentication you want to use. Instead, it checks the remaining duration of the access token and -uses the refresh token to get a new access token if its less than 4 hours remaining. - -```powershell -Connect-GitHubAccount -✓ Access token is still valid for 05:30:41 ... -✓ Logged in as octocat! -``` - -This is also happening automatically when you run a command that requires authentication. The validity of the token is checked before the command is executed. -If it is no longer valid, the token is refreshed and the command is executed. - -```powershell -Connect-GitHubAccount -⚠ Access token remaining validity 01:22:31. Refreshing access token... -✓ Logged in as octocat! -``` - -If the timer has gone out, we still have your back. It will just refresh as long as the refresh token is valid. - -```powershell -Connect-GitHubAccount -⚠ Access token expired. Refreshing access token... -✓ Logged in as octocat! -``` #### Personal authentication - User access tokens with OAuth app @@ -223,6 +196,15 @@ Connect-GitHubAccount -Host 'https://msx.ghe.com' -ClientID 'lv123456789' ✓ Logged in as octocat! ``` +#### Automatic token renewal + +The module automatically manages short‑lived tokens for GitHub Apps: + +- User access tokens (when you authenticate via a GitHub App) are short‑lived and include a refresh token. The module refreshes them automatically before/when they expire—no extra steps are required. +- App JWTs (when the context is a GitHub App) are generated and rotated automatically per call as needed. You never need to create or renew the JWT yourself. + +Note: Long‑lived tokens like classic/fine‑grained PATs and provided installation tokens (GH_TOKEN/GITHUB_TOKEN) are not refreshed by the module. + ### Command Exploration Familiarize yourself with the available cmdlets using the module's comprehensive documentation or inline help. diff --git a/src/classes/public/Config/GitHubConfig.ps1 b/src/classes/public/Config/GitHubConfig.ps1 index ce745b2de..ac8ffd8b8 100644 --- a/src/classes/public/Config/GitHubConfig.ps1 +++ b/src/classes/public/Config/GitHubConfig.ps1 @@ -35,9 +35,6 @@ # The default value for retry interval in seconds. [System.Nullable[int]] $RetryInterval - # The tolerance time in seconds for JWT token validation. - [System.Nullable[int]] $JwtTimeTolerance - # The environment type, which is used to determine the context of the GitHub API calls. [string] $EnvironmentType diff --git a/src/classes/public/Context/GitHubContext.ps1 b/src/classes/public/Context/GitHubContext.ps1 index 8788d051b..7d437c6de 100644 --- a/src/classes/public/Context/GitHubContext.ps1 +++ b/src/classes/public/Context/GitHubContext.ps1 @@ -82,6 +82,7 @@ $this.UserName = $Object.UserName $this.Token = $Object.Token $this.TokenType = $Object.TokenType + $this.TokenExpiresAt = $Object.TokenExpiresAt $this.Enterprise = $Object.Enterprise $this.Owner = $Object.Owner $this.Repository = $Object.Repository diff --git a/src/formats/GitHubConfig.Format.ps1xml b/src/formats/GitHubConfig.Format.ps1xml index 51fb2c86b..cd556ceb4 100644 --- a/src/formats/GitHubConfig.Format.ps1xml +++ b/src/formats/GitHubConfig.Format.ps1xml @@ -31,9 +31,6 @@ AccessTokenGracePeriodInHours - - JwtTimeTolerance - ApiVersion diff --git a/src/formats/GitHubContext.Format.ps1xml b/src/formats/GitHubContext.Format.ps1xml index 90ae28648..45756fbb5 100644 --- a/src/formats/GitHubContext.Format.ps1xml +++ b/src/formats/GitHubContext.Format.ps1xml @@ -58,7 +58,7 @@ return } - if ($_.TokenExpiresIn -lt 0) { + if ($_.TokenExpiresIn -le 0) { $text = 'Expired' } else { $text = $_.TokenExpiresIn.ToString('hh\:mm\:ss') @@ -73,6 +73,9 @@ 'IAT' { $maxValue = [TimeSpan]::FromHours(1) } + 'APP' { + $maxValue = [TimeSpan]::FromMinutes(10) + } } $ratio = [Math]::Min(($_.TokenExpiresIn / $maxValue), 1) [GitHubFormatter]::FormatColorByRatio($ratio, $text) @@ -172,6 +175,12 @@ TokenType + + TokenExpiresAt + + + TokenExpiresIn + HostName @@ -238,22 +247,22 @@ TokenType - HostName + TokenExpiresAt - UserName + TokenExpiresIn - ClientID + HostName - InstallationID + UserName - TokenExpiresAt + ClientID - TokenExpiresIn + InstallationID InstallationType @@ -311,6 +320,12 @@ TokenType + + TokenExpiresAt + + + TokenExpiresIn + HostName @@ -326,12 +341,6 @@ Scope - - TokenExpiresAt - - - TokenExpiresIn - RefreshTokenExpiresAt diff --git a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 index 2d47a9f81..b6aef3d64 100644 --- a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 +++ b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 @@ -45,8 +45,8 @@ } ) $now = [System.DateTimeOffset]::UtcNow - $iat = $now.AddSeconds(-$script:GitHub.Config.JwtTimeTolerance) - $exp = $now.AddSeconds($script:GitHub.Config.JwtTimeTolerance) + $iat = $now.AddMinutes(-10) + $exp = $now.AddMinutes(10) $payload = [GitHubJWTComponent]::ToBase64UrlString( @{ iat = $iat.ToUnixTimeSeconds() diff --git a/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 b/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 index ae705ead3..4db614e1f 100644 --- a/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Test-GitHubJWTRefreshRequired.ps1 @@ -31,7 +31,7 @@ function Test-GitHubJWTRefreshRequired { process { try { - ($Context.TokenExpiresAt - [datetime]::Now).TotalSeconds -le ($script:GitHub.Config.JwtTimeTolerance / 2) + ($Context.TokenExpiresAt - [datetime]::Now).TotalSeconds -le 60 } catch { return $true } diff --git a/src/types/GitHubContext.Types.ps1xml b/src/types/GitHubContext.Types.ps1xml index 2e78158cb..d6cb55a8c 100644 --- a/src/types/GitHubContext.Types.ps1xml +++ b/src/types/GitHubContext.Types.ps1xml @@ -6,7 +6,7 @@ TokenExpiresIn - if ($null -eq $this.TokenExpiresAt) { return } + if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero } $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now if ($timeRemaining.TotalSeconds -lt 0) { return [TimeSpan]::Zero @@ -17,7 +17,7 @@ RefreshTokenExpiresIn - if ($null -eq $this.RefreshTokenExpiresAt) { return } + if ($null -eq $this.RefreshTokenExpiresAt) { return [TimeSpan]::Zero } $timeRemaining = $this.RefreshTokenExpiresAt - [DateTime]::Now if ($timeRemaining.TotalSeconds -lt 0) { return [TimeSpan]::Zero @@ -29,6 +29,22 @@
GitHubAppInstallationContext + + + TokenExpiresIn + + if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero } + $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now + if ($timeRemaining.TotalSeconds -lt 0) { + return [TimeSpan]::Zero + } + return $timeRemaining + + + + + + GitHubAppContext TokenExpiresIn diff --git a/src/variables/private/GitHub.ps1 b/src/variables/private/GitHub.ps1 index 93d1d1344..3891118b3 100644 --- a/src/variables/private/GitHub.ps1 +++ b/src/variables/private/GitHub.ps1 @@ -18,7 +18,6 @@ $script:GitHub = [pscustomobject]@{ PerPage = 100 RetryCount = 0 RetryInterval = 1 - JwtTimeTolerance = 300 EnvironmentType = Get-GitHubEnvironmentType } Config = $null diff --git a/tests/Emojis.Tests.ps1 b/tests/Emojis.Tests.ps1 new file mode 100644 index 000000000..ff3100a2e --- /dev/null +++ b/tests/Emojis.Tests.ps1 @@ -0,0 +1,67 @@ +#Requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '5.7.1' } + +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', '', + Justification = 'Pester grouping syntax: known issue.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'Used to create a secure string for testing.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Log outputs to GitHub Actions logs.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', '', + Justification = 'Long test descriptions and skip switches' +)] +[CmdletBinding()] +param() + +Describe 'Emojis' { + $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" + + Context 'As using on ' -ForEach $authCases { + BeforeAll { + $context = Connect-GitHubAccount @connectParams -PassThru -Silent + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + } + AfterAll { + Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent + Write-Host ('-' * 60) + } + + # Tests for APP goes here + if ($AuthType -eq 'APP') { + It 'Connect-GitHubApp - Connects as a GitHub App to ' { + $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + } + } + + # Tests for runners goes here + if ($Type -eq 'GitHub Actions') {} + + # Tests for IAT UAT and PAT goes here + It 'Get-GitHubEmoji - Gets a list of all emojis' { + $emojis = Get-GitHubEmoji + LogGroup 'emojis' { + Write-Host ($emojis | Format-Table | Out-String) + } + $emojis | Should -Not -BeNullOrEmpty + } + It 'Get-GitHubEmoji - Downloads all emojis' { + Get-GitHubEmoji -Path $Home + LogGroup 'emojis' { + $emojis = Get-ChildItem -Path $Home -File + Write-Host ($emojis | Format-Table | Out-String) + } + $emojis | Should -Not -BeNullOrEmpty + } + } +} diff --git a/tests/GitHub.Tests.ps1 b/tests/GitHub.Tests.ps1 index 988d7a891..53b9e347e 100644 --- a/tests/GitHub.Tests.ps1 +++ b/tests/GitHub.Tests.ps1 @@ -79,6 +79,9 @@ Describe 'Auth' { Write-Host ($context | Format-List | Out-String) } $context | Should -Not -BeNullOrEmpty + $context | Should -BeOfType [GitHubContext] + $context.TokenExpiresAt | Should -BeOfType [DateTime] + $context.TokenExpiresIn | Should -BeOfType [TimeSpan] } It 'Connect-GitHubApp - Connects as a GitHub App to ' -Skip:($AuthType -ne 'APP') { @@ -106,6 +109,8 @@ Describe 'Auth' { LogGroup 'Connect-GithubApp' { $context } + $context.TokenExpiresAt | Should -BeOfType [DateTime] + $context.TokenExpiresIn | Should -BeOfType [TimeSpan] LogGroup 'Context' { Write-Host ($context | Format-List | Out-String) } @@ -763,53 +768,6 @@ Describe 'API' { } } -Describe 'Emojis' { - $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" - - Context 'As using on ' -ForEach $authCases { - BeforeAll { - $context = Connect-GitHubAccount @connectParams -PassThru -Silent - LogGroup 'Context' { - Write-Host ($context | Format-List | Out-String) - } - } - AfterAll { - Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent - Write-Host ('-' * 60) - } - - # Tests for APP goes here - if ($AuthType -eq 'APP') { - It 'Connect-GitHubApp - Connects as a GitHub App to ' { - $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent - LogGroup 'Context' { - Write-Host ($context | Format-List | Out-String) - } - } - } - - # Tests for runners goes here - if ($Type -eq 'GitHub Actions') {} - - # Tests for IAT UAT and PAT goes here - It 'Get-GitHubEmoji - Gets a list of all emojis' { - $emojis = Get-GitHubEmoji - LogGroup 'emojis' { - Write-Host ($emojis | Format-Table | Out-String) - } - $emojis | Should -Not -BeNullOrEmpty - } - It 'Get-GitHubEmoji - Downloads all emojis' { - Get-GitHubEmoji -Path $Home - LogGroup 'emojis' { - $emojis = Get-ChildItem -Path $Home -File - Write-Host ($emojis | Format-Table | Out-String) - } - $emojis | Should -Not -BeNullOrEmpty - } - } -} - Describe 'Webhooks' { BeforeAll { $secret = "It's a Secret to Everybody" From 4bf12ffa34f33850b6d29a9577ae03b505c47036 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 5 Sep 2025 19:31:02 +0200 Subject: [PATCH 27/27] =?UTF-8?q?=F0=9F=AA=B2=20[Fix]:=20Fix=20an=20issue?= =?UTF-8?q?=20with=20all=20App/JWT=20tokens=20being=20marked=20as=20expire?= =?UTF-8?q?d=20(#497)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request updates the handling of JWT token issue and expiry times, ensuring consistent use of local time and simplifying the calculation of token expiry intervals. The changes improve time zone handling and streamline the logic for determining token validity. **Improvements to JWT Time Handling:** * Changed the calculation of `IssuedAt` and `ExpiresAt` in `New-GitHubUnsignedJWT.ps1` to use `LocalDateTime` instead of `DateTime`, ensuring the times are always in local time. * In `Update-GitHubAppJWT.ps1`, added logic to convert `ExpiresAt` from UTC to local time if needed before updating the context, further standardizing time zone usage. **Simplification of Token Expiry Calculation:** * Simplified the `TokenExpiresIn` and `RefreshTokenExpiresIn` script properties in `GitHubContext.Types.ps1xml` by removing redundant checks for negative intervals and directly returning the time difference. ## Type of change - [ ] 📖 [Docs] - [x] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas --- .../GitHub Apps/New-GitHubUnsignedJWT.ps1 | 10 ++++---- .../Apps/GitHub Apps/Update-GitHubAppJWT.ps1 | 7 ++++-- src/types/GitHubContext.Types.ps1xml | 24 ++++--------------- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 index b6aef3d64..16d3264cc 100644 --- a/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 +++ b/src/functions/private/Apps/GitHub Apps/New-GitHubUnsignedJWT.ps1 @@ -44,9 +44,9 @@ typ = 'JWT' } ) - $now = [System.DateTimeOffset]::UtcNow - $iat = $now.AddMinutes(-10) - $exp = $now.AddMinutes(10) + $nowUtc = [System.DateTimeOffset]::UtcNow + $iat = $nowUtc.AddMinutes(-10) + $exp = $nowUtc.AddMinutes(10) $payload = [GitHubJWTComponent]::ToBase64UrlString( @{ iat = $iat.ToUnixTimeSeconds() @@ -56,8 +56,8 @@ ) [pscustomobject]@{ Base = "$header.$payload" - IssuedAt = $iat.DateTime - ExpiresAt = $exp.DateTime + IssuedAt = $iat.LocalDateTime + ExpiresAt = $exp.LocalDateTime Issuer = $ClientID } } diff --git a/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 b/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 index 350a47434..e9f6892e4 100644 --- a/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Update-GitHubAppJWT.ps1 @@ -92,7 +92,11 @@ throw 'No Private Key or KeyVault Key Reference provided in the context.' } - $Context.TokenExpiresAt = $unsignedJWT.ExpiresAt + $expiresAt = $unsignedJWT.ExpiresAt + if ($expiresAt.Kind -eq [DateTimeKind]::Utc) { + $expiresAt = $expiresAt.ToLocalTime() + } + $Context.TokenExpiresAt = $expiresAt if ($Context.ID) { if ($PSCmdlet.ShouldProcess('JWT token', 'Update/refresh')) { @@ -122,7 +126,6 @@ } } } else { - # JWT is still valid, no refresh needed Write-Debug 'JWT is still valid, no refresh needed' } diff --git a/src/types/GitHubContext.Types.ps1xml b/src/types/GitHubContext.Types.ps1xml index d6cb55a8c..6ea11368c 100644 --- a/src/types/GitHubContext.Types.ps1xml +++ b/src/types/GitHubContext.Types.ps1xml @@ -7,22 +7,14 @@ TokenExpiresIn if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero } - $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now - if ($timeRemaining.TotalSeconds -lt 0) { - return [TimeSpan]::Zero - } - return $timeRemaining + $this.TokenExpiresAt - [DateTime]::Now RefreshTokenExpiresIn if ($null -eq $this.RefreshTokenExpiresAt) { return [TimeSpan]::Zero } - $timeRemaining = $this.RefreshTokenExpiresAt - [DateTime]::Now - if ($timeRemaining.TotalSeconds -lt 0) { - return [TimeSpan]::Zero - } - return $timeRemaining + $this.RefreshTokenExpiresAt - [DateTime]::Now @@ -34,11 +26,7 @@ TokenExpiresIn if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero } - $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now - if ($timeRemaining.TotalSeconds -lt 0) { - return [TimeSpan]::Zero - } - return $timeRemaining + $this.TokenExpiresAt - [DateTime]::Now @@ -50,11 +38,7 @@ TokenExpiresIn if ($null -eq $this.TokenExpiresAt) { return } - $timeRemaining = $this.TokenExpiresAt - [DateTime]::Now - if ($timeRemaining.TotalSeconds -lt 0) { - return [TimeSpan]::Zero - } - return $timeRemaining + $this.TokenExpiresAt - [DateTime]::Now