From 3367f903e8835dfb04fcd2d18cad329c8f3408ff Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 12 Jun 2025 13:31:45 +0200 Subject: [PATCH] =?UTF-8?q?=20=F0=9F=9A=80=20[Feature]:=20Add=20class=20fo?= =?UTF-8?q?r=20`GitHubApp`=20and=20`GitHubAppInstallation`=20(#406)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request introduces significant enhancements to the GitHub Apps module by adding new classes, improving type safety, and refining existing functions. The changes focus on creating structured representations for GitHub Apps and their installations, updating function outputs to use these new types, and improving parameter handling for better usability and clarity. ### New Classes for GitHub Apps and Installations: * [`src/classes/public/App/GitHubApp.ps1`](diffhunk://#diff-067422a4a7efa7c966720b01cb15b3868f47b408676fd32b13c0d0a5fd13f28fR1-R66): Introduced the `GitHubApp` class to encapsulate properties and methods for GitHub Apps, including `ID`, `ClientID`, `Slug`, `Permissions`, and `Events`. This improves type safety and enables structured handling of app data. * [`src/classes/public/App/GitHubAppInstallation.ps1`](diffhunk://#diff-c1442a9fa3e51d2f0bf378039e97400122a24423d72d534112ca6f7c06a5ffaeR1-R63): Added the `GitHubAppInstallation` class to represent app installations, including `ID`, `Target`, `Permissions`, and `CreatedAt`. This facilitates better organization and manipulation of installation data. ### Updates to Function Outputs: * [`src/functions/private/Apps/GitHub Apps/Get-GitHubAppByName.ps1`](diffhunk://#diff-2446812fa850e0b15e44ea484a0ef116efbe4b5d7e22b74960faf084b4015256L17-R17): Changed output type from `[pscustomobject]` to `[GitHubApp]` and updated the response handling to instantiate `GitHubApp` objects. [[1]](diffhunk://#diff-2446812fa850e0b15e44ea484a0ef116efbe4b5d7e22b74960faf084b4015256L17-R17) [[2]](diffhunk://#diff-2446812fa850e0b15e44ea484a0ef116efbe4b5d7e22b74960faf084b4015256L46-R46) * [`src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1`](diffhunk://#diff-f58f23b4edc1de29c735a7576182208d9f0d4908650818560c1d5a20e4a59674R17-R29): Updated output type to `[GitHubAppInstallation[]]` and modified response processing to create instances of `GitHubAppInstallation`. [[1]](diffhunk://#diff-f58f23b4edc1de29c735a7576182208d9f0d4908650818560c1d5a20e4a59674R17-R29) [[2]](diffhunk://#diff-f58f23b4edc1de29c735a7576182208d9f0d4908650818560c1d5a20e4a59674R45-R52) * [`src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1`](diffhunk://#diff-cb918ad0c83be9fde80efae340f437639173ba82a5a363ef7b1a9be93e05dfd5L19-R19): Updated output type to `[GitHubAppInstallation]` and adjusted response handling for better type safety. [[1]](diffhunk://#diff-cb918ad0c83be9fde80efae340f437639173ba82a5a363ef7b1a9be93e05dfd5L19-R19) [[2]](diffhunk://#diff-cb918ad0c83be9fde80efae340f437639173ba82a5a363ef7b1a9be93e05dfd5L61-R61) ### Refinements to Parameter Handling: * [`src/functions/public/Apps/GitHub App/Get-GitHubApp.ps1`](diffhunk://#diff-eb4b0ed1f801228094dc7d155d3b2cd9a7a417d294ead8583bdfa87e455efcd5L27-R36): Improved parameter set names for clarity, such as renaming `'BySlug'` to `'Get an app by slug'`. Added alias `Slug` for the `Name` parameter to enhance usability. [[1]](diffhunk://#diff-eb4b0ed1f801228094dc7d155d3b2cd9a7a417d294ead8583bdfa87e455efcd5L27-R36) [[2]](diffhunk://#diff-eb4b0ed1f801228094dc7d155d3b2cd9a7a417d294ead8583bdfa87e455efcd5L53-R53) * [`src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallation.ps1`](diffhunk://#diff-9ca965372ef6314e8f8759ce87dedff3c8a0d216fe06fda41e0fb38b89722dfeL14-R39): Refined parameter sets to clearly differentiate between listing installations for enterprises, organizations, and authenticated apps. [[1]](diffhunk://#diff-9ca965372ef6314e8f8759ce87dedff3c8a0d216fe06fda41e0fb38b89722dfeL14-R39) [[2]](diffhunk://#diff-9ca965372ef6314e8f8759ce87dedff3c8a0d216fe06fda41e0fb38b89722dfeL55-R74) ### Adjustments to Existing Classes: * [`src/classes/public/Owner/GitHubOwner.ps1`](diffhunk://#diff-41f600a6b5b0e373d0e53465e24c629e95b33f9864c206542e843fc2a269bcabL78-R84): Updated property mappings to handle both `slug` and `login` for `Name` and added fallback for `Blog` using `website_url`. ### Context Improvements: * [`src/functions/private/Auth/Context/Set-GitHubContext.ps1`](diffhunk://#diff-600a257f8ea7acdd36413aef2daf597ab69dd5bb3c17ec7d6fed83e15f0af1d7L81-R81): Updated context object properties to use the new `GitHubApp` class, ensuring consistency and type safety across app-related context data. [[1]](diffhunk://#diff-600a257f8ea7acdd36413aef2daf597ab69dd5bb3c17ec7d6fed83e15f0af1d7L81-R81) [[2]](diffhunk://#diff-600a257f8ea7acdd36413aef2daf597ab69dd5bb3c17ec7d6fed83e15f0af1d7L125-R133) ## 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/EnterpriseApps.ps1 | 6 +- src/classes/public/App/GitHubApp.ps1 | 66 ++++++++++ .../public/App/GitHubAppInstallation.ps1 | 63 ++++++++++ src/classes/public/Owner/GitHubOwner.ps1 | 4 +- .../Apps/GitHub Apps/Get-GitHubAppByName.ps1 | 4 +- .../Get-GitHubAppInstallableOrganization.ps1 | 4 + ...tHubAppInstallationForAuthenticatedApp.ps1 | 13 +- .../Get-GitHubAuthenticatedApp.ps1 | 4 +- ...bEnterpriseOrganizationAppInstallation.ps1 | 4 +- .../Get-GitHubOrganizationAppInstallation.ps1 | 6 +- .../Auth/Context/Set-GitHubContext.ps1 | 20 ++-- .../Get-GitHubAppAccessibleRepository.ps1 | 9 +- .../Get-GitHubAppInstallation.ps1 | 32 ++--- .../public/Apps/GitHub App/Get-GitHubApp.ps1 | 8 +- .../public/Auth/Connect-GitHubApp.ps1 | 20 ++-- .../Auth/Connect-GitHubApp_completer.ps1 | 12 +- tests/GitHub.Tests.ps1 | 113 +++++++++++++----- tests/Variables.Tests.ps1 | 8 +- 18 files changed, 302 insertions(+), 94 deletions(-) create mode 100644 src/classes/public/App/GitHubApp.ps1 create mode 100644 src/classes/public/App/GitHubAppInstallation.ps1 diff --git a/examples/Apps/EnterpriseApps.ps1 b/examples/Apps/EnterpriseApps.ps1 index f06cbfaa7..2526b7b2d 100644 --- a/examples/Apps/EnterpriseApps.ps1 +++ b/examples/Apps/EnterpriseApps.ps1 @@ -20,11 +20,11 @@ filter Install-GithubApp { ) process { - $installableOrgs = Get-GitHubOrganization -Enterprise $Enterprise -Debug -Verbose + $installableOrgs = Get-GitHubOrganization -Enterprise $Enterprise $orgs = $installableOrgs | Where-Object { $_.login -like $organization } foreach ($org in $orgs) { foreach ($appIDitem in $AppID) { - Install-GitHubAppOnEnterpriseOrganization -Enterprise $Enterprise -Organization $org.login -ClientID $appIDitem -RepositorySelection all | ForEach-Object { + Install-GitHubApp -Enterprise $Enterprise -Organization $org.login -ClientID $appIDitem -RepositorySelection all | ForEach-Object { [PSCustomObject]@{ Organization = $org.login AppID = $appIDitem @@ -35,6 +35,6 @@ filter Install-GithubApp { } } -$appIDs | Install-GitHubApp -Organization $organization -Debug -Verbose +$appIDs | Install-GitHubApp -Organization $organization $installation = Get-GitHubAppInstallation diff --git a/src/classes/public/App/GitHubApp.ps1 b/src/classes/public/App/GitHubApp.ps1 new file mode 100644 index 000000000..f570eabce --- /dev/null +++ b/src/classes/public/App/GitHubApp.ps1 @@ -0,0 +1,66 @@ +class GitHubApp : GitHubNode { + # The unique ID of the app + [System.Nullable[UInt64]] $ID + + # The Client ID of the app + [string] $ClientID + + # The App ID of the app + [System.Nullable[UInt64]] $AppID + + # The Slug of the app + [string] $Slug + + # The node_id of the app + [string] $NodeID + + # The owner of the app. + [GitHubOwner] $Owner + + # The name of the app + [string] $Name + + # The description of the app + [string] $Description + + # The external URL of the app + [string] $ExternalUrl + + # The HTML URL of the app + [string] $Url + + # The creation date of the app + [System.Nullable[datetime]] $CreatedAt + + # The last update date of the app + [System.Nullable[datetime]] $UpdatedAt + + # The permissions that the app is requesting. + [pscustomobject] $Permissions + + # The events that the app is subscribing to on its target. + [string[]] $Events + + # The number of installations + [System.Nullable[int]] $Installations + + GitHubApp() {} + + GitHubApp([object]$Object) { + $this.ID = $Object.id + $this.ClientID = $Object.client_id + $this.AppID = $Object.app_id + $this.Slug = $Object.app_slug ?? $Object.slug + $this.NodeID = $Object.node_id + $this.Owner = [GitHubOwner]::new($Object.owner) + $this.Name = $Object.name + $this.Description = $Object.description + $this.ExternalUrl = $Object.external_url + $this.Url = $Object.html_url + $this.CreatedAt = $Object.created_at + $this.UpdatedAt = $Object.updated_at + $this.Permissions = $Object.permissions + $this.Events = , ($Object.events) + $this.Installations = $Object.installations_count + } +} diff --git a/src/classes/public/App/GitHubAppInstallation.ps1 b/src/classes/public/App/GitHubAppInstallation.ps1 new file mode 100644 index 000000000..6684d77f4 --- /dev/null +++ b/src/classes/public/App/GitHubAppInstallation.ps1 @@ -0,0 +1,63 @@ +class GitHubAppInstallation { + # The installation ID on the target. + [System.Nullable[UInt64]] $ID + + # The app that is installed. + [GitHubApp] $App + + # The target of the installation. + [GitHubOwner] $Target + + # The type of target. + [string] $Type + + # The type of repository selection. + [string] $RepositorySelection + + # The permissions that the app has on the target. + [pscustomobject] $Permissions + + # The events that the app is subscribing to. + [string[]] $Events + + # The file paths that the app has access to. + [string[]] $FilePaths + + # The creation date of the installation. + # Example: 2008-01-14T04:33:35Z + [System.Nullable[datetime]] $CreatedAt + + # The last update date of the installation. + # Example: 2008-01-14T04:33:35Z + [System.Nullable[datetime]] $UpdatedAt + + # The date the installation was suspended. + # Example: 2008-01-14T04:33:35Z + [System.Nullable[datetime]] $SuspendedAt + + # The account that suspended the installation. + [GitHubUser] $SuspendedBy + + GitHubAppInstallation() {} + + GitHubAppInstallation([PSCustomObject]$Object) { + $this.ID = $Object.id + $this.App = [GitHubApp]::new( + [PSCustomObject]@{ + client_id = $Object.client_id + app_id = $Object.app_id + app_slug = $Object.app_slug + } + ) + $this.Target = [GitHubOwner]::new($Object.account) + $this.Type = $Object.target_type + $this.RepositorySelection = $Object.repository_selection + $this.Permissions = $Object.permissions + $this.Events = , ($Object.events) + $this.FilePaths = $Object.single_file_paths + $this.CreatedAt = $Object.created_at + $this.UpdatedAt = $Object.updated_at + $this.SuspendedAt = $Object.suspended_at + $this.SuspendedBy = [GitHubUser]::new($Object.suspended_by) + } +} diff --git a/src/classes/public/Owner/GitHubOwner.ps1 b/src/classes/public/Owner/GitHubOwner.ps1 index 4c56bbc2a..96345cb84 100644 --- a/src/classes/public/Owner/GitHubOwner.ps1 +++ b/src/classes/public/Owner/GitHubOwner.ps1 @@ -75,13 +75,13 @@ $this.NodeID = $Object.node_id # From GitHubOwner - $this.Name = $Object.login + $this.Name = $Object.slug ?? $Object.login $this.DisplayName = $Object.name $this.AvatarUrl = $Object.avatar_url $this.Url = $Object.html_url $this.Type = $Object.type $this.Company = $Object.company - $this.Blog = $Object.blog + $this.Blog = $Object.website_url ?? $Object.blog $this.Location = $Object.location $this.Email = $Object.email $this.TwitterUsername = $Object.twitter_username diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppByName.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppByName.ps1 index 260e22f78..4cab84652 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppByName.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppByName.ps1 @@ -14,7 +14,7 @@ .NOTES [Get an app](https://docs.github.com/rest/apps/apps#get-an-app) #> - [OutputType([pscustomobject])] + [OutputType([GitHubApp])] [CmdletBinding()] param( # The AppSlug is just the URL-friendly name of a GitHub App. @@ -43,7 +43,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + [GitHubApp]::new($_.Response) } } end { diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 index a53e7eca8..c179a6a3f 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallableOrganization.ps1 @@ -13,9 +13,13 @@ .EXAMPLE Get-GitHubAppInstallableOrganization -Enterprise 'msx' + .OUTPUTS + GitHubOrganization[] + .LINK https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Get-GitHubAppInstallableOrganization #> + [OutputType([GitHubOrganization[]])] [CmdletBinding()] param( # The enterprise slug or ID. diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 index 43f409f6c..c7e3c6d1b 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAppInstallationForAuthenticatedApp.ps1 @@ -14,11 +14,19 @@ List installations for the authenticated app. + .OUTPUTS + GitHubAppInstallation[] + .NOTES [List installations for the authenticated app](https://docs.github.com/rest/apps/apps#list-installations-for-the-authenticated-app) #> + [OutputType([GitHubAppInstallation])] [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. [Parameter(Mandatory)] [object] $Context @@ -34,11 +42,14 @@ $inputObject = @{ Context = $Context APIEndpoint = '/app/installations' + PerPage = $PerPage Method = 'GET' } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + $_.Response | ForEach-Object { + [GitHubAppInstallation]::new($_) + } } } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 index f7f0c4cba..bfa58d061 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubAuthenticatedApp.ps1 @@ -20,7 +20,7 @@ .NOTES [Get the authenticated app](https://docs.github.com/rest/apps/apps#get-an-app) #> - [OutputType([pscustomobject])] + [OutputType([GitHubApp])] [CmdletBinding()] param( # The context to run the command in. Used to get the details for the API call. @@ -42,7 +42,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + [GitHubApp]::new($_.Response) } } end { diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 index baf4d38d6..bdad499f8 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 @@ -16,7 +16,7 @@ .NOTES [List GitHub Apps installed on an enterprise-owned organization]() #> - [OutputType([pscustomobject])] + [OutputType([GitHubAppInstallation])] [CmdletBinding()] param( # The enterprise slug or ID. @@ -58,7 +58,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + [GitHubAppInstallation]::new($_.Response) } } diff --git a/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 b/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 index 692ed4ed5..90c442354 100644 --- a/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 +++ b/src/functions/private/Apps/GitHub Apps/Get-GitHubOrganizationAppInstallation.ps1 @@ -15,7 +15,7 @@ .NOTES [List app installations for an organization](https://docs.github.com/rest/orgs/orgs#list-app-installations-for-an-organization) #> - [OutputType([pscustomobject])] + [OutputType([GitHubAppInstallation])] [CmdletBinding()] param( # The organization name. The name is not case sensitive. @@ -50,7 +50,9 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response.installations + $_.Response.installations | ForEach-Object { + [GitHubAppInstallation]::new($_) + } } } diff --git a/src/functions/private/Auth/Context/Set-GitHubContext.ps1 b/src/functions/private/Auth/Context/Set-GitHubContext.ps1 index d96d925b5..1a7cf2eb9 100644 --- a/src/functions/private/Auth/Context/Set-GitHubContext.ps1 +++ b/src/functions/private/Auth/Context/Set-GitHubContext.ps1 @@ -78,7 +78,7 @@ if ([string]::IsNullOrEmpty($contextObj['DisplayName'])) { try { $app = Get-GitHubApp -Name $contextObj['Username'] -Context $contextObj - $contextObj['DisplayName'] = [string]$app.name + $contextObj['DisplayName'] = [string]$app.Name } catch { Write-Debug "Failed to get the GitHub App with the slug: [$($contextObj['Username'])]." } @@ -122,15 +122,15 @@ } 'App' { $app = Get-GitHubApp -Context $contextObj - $contextObj['Name'] = "$($contextObj['HostName'])/$($app.slug)" - $contextObj['DisplayName'] = [string]$app.name - $contextObj['Username'] = [string]$app.slug - $contextObj['NodeID'] = [string]$app.node_id - $contextObj['DatabaseID'] = [string]$app.id - $contextObj['Permissions'] = [PSCustomObject]$app.permissions - $contextObj['Events'] = [string[]]$app.events - $contextObj['OwnerName'] = [string]$app.owner.login - $contextObj['OwnerType'] = [string]$app.owner.type + $contextObj['Name'] = "$($contextObj['HostName'])/$($app.Slug)" + $contextObj['DisplayName'] = [string]$app.Name + $contextObj['Username'] = [string]$app.Slug + $contextObj['NodeID'] = [string]$app.NodeID + $contextObj['DatabaseID'] = [string]$app.ID + $contextObj['Permissions'] = [PSCustomObject]$app.Permissions + $contextObj['Events'] = [string[]]$app.Events + $contextObj['OwnerName'] = [string]$app.Owner.Name + $contextObj['OwnerType'] = [string]$app.Owner.Type $contextObj['Type'] = 'App' } default { 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 4cee89486..133976f18 100644 --- a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppAccessibleRepository.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppAccessibleRepository.ps1 @@ -19,9 +19,16 @@ Get the repositories that can be made accessible to a GitHub App installed on the organization 'PSModule' in the enterprise 'msx'. + .OUTPUTS + GitHubRepository[] + .LINK https://psmodule.io/GitHub/Functions/Apps/GitHub%20App%20Installations/Get-GitHubAppAccessibleRepository + + .NOTES + #> + [OutputType([GitHubRepository[]])] [CmdletBinding(SupportsShouldProcess)] param( # The enterprise slug or ID. @@ -65,7 +72,7 @@ } Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + [GitHubRepository]::($_.Response) } } diff --git a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallation.ps1 b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallation.ps1 index bac0de97b..856252aa0 100644 --- a/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallation.ps1 +++ b/src/functions/public/Apps/GitHub App Installations/Get-GitHubAppInstallation.ps1 @@ -11,13 +11,14 @@ .LINK https://psmodule.io/GitHub/Functions/Apps/GitHub%20App%20Installations/Get-GitHubAppInstallation #> - [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] + [OutputType([GitHubAppInstallation[]])] + [CmdletBinding(DefaultParameterSetName = 'List installations for the authenticated app')] param( # The enterprise slug or ID. [Parameter( Mandatory, ValueFromPipelineByPropertyName, - ParameterSetName = 'Enterprise' + ParameterSetName = 'List installations on an Enterprise' )] [string] $Enterprise, @@ -25,18 +26,17 @@ [Parameter( Mandatory, ValueFromPipelineByPropertyName, - ParameterSetName = 'Enterprise' + ParameterSetName = 'List installations on an Enterprise' )] [Parameter( Mandatory, ValueFromPipelineByPropertyName, - ParameterSetName = 'Organization' + ParameterSetName = 'List installations on an Organization' )] [string] $Organization, # The number of results per page (max 100). - [Parameter(ParameterSetName = 'Enterprise')] - [Parameter(ParameterSetName = 'Organization')] + [Parameter()] [System.Nullable[int]] $PerPage, # The context to run the command in. Used to get the details for the API call. @@ -52,26 +52,26 @@ } process { + $params = @{ + PerPage = $PerPage + Context = $Context + } switch ($PSCmdlet.ParameterSetName) { - 'Enterprise' { - $params = @{ + 'List installations on an Enterprise' { + $params += @{ Enterprise = $Enterprise Organization = $Organization - PerPage = $PerPage - Context = $Context } Get-GitHubEnterpriseOrganizationAppInstallation @params } - 'Organization' { - $params = @{ + 'List installations on an Organization' { + $params += @{ Organization = $Organization - PerPage = $PerPage - Context = $Context } Get-GitHubOrganizationAppInstallation @params } - default { - Get-GitHubAppInstallationForAuthenticatedApp -Context $Context + 'List installations for the authenticated app' { + Get-GitHubAppInstallationForAuthenticatedApp @params } } } diff --git a/src/functions/public/Apps/GitHub App/Get-GitHubApp.ps1 b/src/functions/public/Apps/GitHub App/Get-GitHubApp.ps1 index f675e0163..6e678b585 100644 --- a/src/functions/public/Apps/GitHub App/Get-GitHubApp.ps1 +++ b/src/functions/public/Apps/GitHub App/Get-GitHubApp.ps1 @@ -24,16 +24,16 @@ https://psmodule.io/GitHub/Functions/Apps/GitHub%20App/Get-GitHubApp #> [OutputType([pscustomobject])] - [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] + [CmdletBinding(DefaultParameterSetName = 'Get the authenticated app')] param( # The AppSlug is just the URL-friendly name of a GitHub App. # You can find this on the settings page for your GitHub App (e.g., ). # Example: 'github-actions' [Parameter( Mandatory, - ParameterSetName = 'BySlug' + ParameterSetName = 'Get an app by slug' )] - [Alias('AppSlug')] + [Alias('AppSlug', 'Slug')] [string] $Name, # The context to run the command in. Used to get the details for the API call. @@ -50,7 +50,7 @@ process { switch ($PSCmdlet.ParameterSetName) { - 'BySlug' { + 'Get an app by slug' { Get-GitHubAppByName -AppSlug $Name -Context $Context } default { diff --git a/src/functions/public/Auth/Connect-GitHubApp.ps1 b/src/functions/public/Auth/Connect-GitHubApp.ps1 index bac6f7ace..dd11923d2 100644 --- a/src/functions/public/Auth/Connect-GitHubApp.ps1 +++ b/src/functions/public/Auth/Connect-GitHubApp.ps1 @@ -95,21 +95,21 @@ $userItem = $_ Write-Verbose "User filter: [$userItem]." $selectedInstallations += $installations | Where-Object { - $_.target_type -eq 'User' -and $_.account.login -like $userItem + $_.Type -eq 'User' -and $_.Target.Name -like $userItem } } $Organization | ForEach-Object { $organizationItem = $_ Write-Verbose "Organization filter: [$organizationItem]." $selectedInstallations += $installations | Where-Object { - $_.target_type -eq 'Organization' -and $_.account.login -like $organizationItem + $_.Type -eq 'Organization' -and $_.Target.Name -like $organizationItem } } $Enterprise | ForEach-Object { $enterpriseItem = $_ Write-Verbose "Enterprise filter: [$enterpriseItem]." $selectedInstallations += $installations | Where-Object { - $_.target_type -eq 'Enterprise' -and $_.account.slug -like $enterpriseItem + $_.Type -eq 'Enterprise' -and $_.Target.Name -like $enterpriseItem } } } @@ -122,7 +122,7 @@ Write-Verbose "Found [$($selectedInstallations.Count)] installations for the target." $selectedInstallations | ForEach-Object { $installation = $_ - Write-Verbose "Processing installation [$($installation.account.login)] [$($installation.id)]" + Write-Verbose "Processing installation [$($installation.Target.Name)] [$($installation.id)]" $token = New-GitHubAppInstallationAccessToken -Context $Context -InstallationID $installation.id $contextParams = @{ @@ -138,19 +138,19 @@ InstallationID = [string]$installation.id Permissions = [pscustomobject]$installation.permissions Events = [string[]]$installation.events - InstallationType = [string]$installation.target_type + InstallationType = [string]$installation.Type Token = [securestring]$token.Token TokenExpirationDate = [datetime]$token.ExpiresAt } - switch ($installation.target_type) { + switch ($installation.Type) { 'User' { - $contextParams['InstallationName'] = [string]$installation.account.login - $contextParams['Owner'] = [string]$installation.account.login + $contextParams['InstallationName'] = [string]$installation.Target.Name + $contextParams['Owner'] = [string]$installation.Target.Name } 'Organization' { - $contextParams['InstallationName'] = [string]$installation.account.login - $contextParams['Owner'] = [string]$installation.account.login + $contextParams['InstallationName'] = [string]$installation.Target.Name + $contextParams['Owner'] = [string]$installation.Target.Name } 'Enterprise' { $contextParams['InstallationName'] = [string]$installation.account.slug diff --git a/src/functions/public/Auth/Connect-GitHubApp_completer.ps1 b/src/functions/public/Auth/Connect-GitHubApp_completer.ps1 index 94c2b93dc..2dcf1938f 100644 --- a/src/functions/public/Auth/Connect-GitHubApp_completer.ps1 +++ b/src/functions/public/Auth/Connect-GitHubApp_completer.ps1 @@ -2,26 +2,26 @@ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter - Get-GitHubAppInstallation -Verbose:$false | Where-Object { $_.target_type -eq 'User' -and $_.account.login -like "$wordToComplete*" } | + Get-GitHubAppInstallation -Verbose:$false | Where-Object { $_.Type -eq 'User' -and $_.Target.Name -like "$wordToComplete*" } | ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_.account.login, $_.account.login, 'ParameterValue', $_.account.login) + [System.Management.Automation.CompletionResult]::new($_.Target.Name, $_.Target.Name, 'ParameterValue', $_.Target.Name) } } Register-ArgumentCompleter -CommandName Connect-GitHubApp -ParameterName Organization -ScriptBlock { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter - Get-GitHubAppInstallation -Verbose:$false | Where-Object { $_.target_type -eq 'Organization' -and $_.account.login -like "$wordToComplete*" } | + Get-GitHubAppInstallation -Verbose:$false | Where-Object { $_.Type -eq 'Organization' -and $_.Target.Name -like "$wordToComplete*" } | ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_.account.login, $_.account.login, 'ParameterValue', $_.account.login) + [System.Management.Automation.CompletionResult]::new($_.Target.Name, $_.Target.Name, 'ParameterValue', $_.Target.Name) } } Register-ArgumentCompleter -CommandName Connect-GitHubApp -ParameterName Enterprise -ScriptBlock { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter - Get-GitHubAppInstallation -Verbose:$false | Where-Object { $_.target_type -eq 'Enterprise' -and $_.account.slug -like "$wordToComplete*" } | + Get-GitHubAppInstallation -Verbose:$false | Where-Object { $_.Type -eq 'Enterprise' -and $_.Target.Name -like "$wordToComplete*" } | ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_.account.slug, $_.account.slug, 'ParameterValue', $_.account.slug) + [System.Management.Automation.CompletionResult]::new($_.Target.Name, $_.Target.Name, 'ParameterValue', $_.Target.Name) } } diff --git a/tests/GitHub.Tests.ps1 b/tests/GitHub.Tests.ps1 index 666f5eb6d..82964fea3 100644 --- a/tests/GitHub.Tests.ps1 +++ b/tests/GitHub.Tests.ps1 @@ -61,31 +61,34 @@ Describe 'Auth' { $context | Should -Not -BeNullOrEmpty } - # Tests for APP goes here - if ($AuthType -eq 'APP') { - It 'Connect-GitHubAccount - Connects using the provided credentials + AutoloadInstallations' { + It 'Connect-GitHubAccount - Connects using the provided credentials + AutoloadInstallations' -Skip:($AuthType -ne 'APP') { + LogGroup 'Connect-Github' { $context = Connect-GitHubAccount @connectParams -PassThru -Silent -AutoloadInstallations - LogGroup 'Context' { - Write-Host ($context | Format-List | Out-String) - } - $context | Should -Not -BeNullOrEmpty } + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + $context | Should -Not -BeNullOrEmpty + } - It 'Connect-GitHubApp - Connects as a GitHub App to ' { + It 'Connect-GitHubApp - Connects as a GitHub App to ' -Skip:($AuthType -ne 'APP') { + LogGroup 'Connect-GithubApp' { $contexts = Connect-GitHubApp -PassThru -Silent - LogGroup 'Contexts' { - Write-Host ($contexts | Format-List | Out-String) - } - $contexts | Should -Not -BeNullOrEmpty } + LogGroup 'Contexts' { + Write-Host ($contexts | Format-List | Out-String) + } + $contexts | Should -Not -BeNullOrEmpty + } - It 'Connect-GitHubApp - Connects as a GitHub App to ' { + It 'Connect-GitHubApp - Connects as a GitHub App to ' -Skip:($AuthType -ne 'APP') { + LogGroup 'Connect-GithubApp' { $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent - LogGroup 'Context' { - Write-Host ($context | Format-List | Out-String) - } - $context | Should -Not -BeNullOrEmpty } + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + $context | Should -Not -BeNullOrEmpty } # Tests for runners goes here @@ -135,8 +138,10 @@ Describe 'Auth' { Describe 'GitHub' { Context 'Config' { It 'Get-GitHubConfig - Gets the module configuration' { - $config = Get-GitHubConfig - Write-Host ($config | Format-Table | Out-String) + LogGroup 'Config' { + $config = Get-GitHubConfig + Write-Host ($config | Format-List | Out-String) + } $config | Should -Not -BeNullOrEmpty } It 'Get-GitHubConfig - Gets a configuration item by name' { @@ -163,14 +168,18 @@ Describe 'GitHub' { } Context 'Actions' { It 'Get-GitHubEventData - Gets data about the event that triggered the workflow' { - $workflow = Get-GitHubEventData - Write-Host ($workflow | Format-List | Out-String) - $workflow | Should -Not -BeNullOrEmpty + LogGroup 'Event Data' { + $eventData = Get-GitHubEventData + Write-Host ($eventData | Format-List | Out-String) + } + $eventData | Should -Not -BeNullOrEmpty } It 'Get-GitHubRunnerData - Gets data about the runner that is running the workflow' { - $workflow = Get-GitHubRunnerData - Write-Host ($workflow | Format-List | Out-String) - $workflow | Should -Not -BeNullOrEmpty + LogGroup 'Runner Data' { + $runnerData = Get-GitHubRunnerData + Write-Host ($runnerData | Format-List | Out-String) + } + $runnerData | Should -Not -BeNullOrEmpty } } Context 'Status' -ForEach @('Public', 'Europe', 'Australia') { @@ -391,10 +400,32 @@ Describe 'Apps' { It 'Get-GitHubApp - Can get app details' { $app = Get-GitHubApp LogGroup 'App' { - Write-Host ($app | Format-Table | Out-String) + Write-Host ($app | Format-List | Out-String) } $app | Should -Not -BeNullOrEmpty - } + $app | Should -BeOfType 'GitHubApp' + $app.ID | Should -Not -BeNullOrEmpty + $app.ClientID | Should -Not -BeNullOrEmpty + $app.Slug | Should -Not -BeNullOrEmpty + $app.NodeID | Should -Not -BeNullOrEmpty + $app.Owner | Should -BeOfType 'GitHubOwner' + $app.Name | Should -Not -BeNullOrEmpty + $app.Description | Should -Not -BeNullOrEmpty + $app.ExternalUrl | Should -Not -BeNullOrEmpty + $app.Url | Should -Not -BeNullOrEmpty + $app.CreatedAt | Should -Not -BeNullOrEmpty + $app.UpdatedAt | Should -Not -BeNullOrEmpty + $app.Permissions | Should -BeOfType 'PSCustomObject' + $app.Events | Should -BeOfType 'string' + $app.Installations | Should -Not -BeNullOrEmpty + } + # It 'Get-GitHubApp - Get an app by slug' { + # $app = Get-GitHubApp -Name 'github-actions' + # LogGroup 'App by slug' { + # Write-Host ($app | Format-Table | Out-String) + # } + # $app | Should -Not -BeNullOrEmpty + # } It 'Get-GitHubAppJSONWebToken - Can get a JWT for the app' { $jwt = Get-GitHubAppJSONWebToken @connectParams @@ -407,16 +438,34 @@ Describe 'Apps' { It 'Get-GitHubAppInstallation - Can get app installations' { $installations = Get-GitHubAppInstallation LogGroup 'Installations' { - Write-Host ($installations | Format-Table | Out-String) + Write-Host ($installations | Format-List | Out-String) } $installations | Should -Not -BeNullOrEmpty + $githubApp = Get-GitHubApp + foreach ($installation in $installations) { + $installation | Should -BeOfType 'GitHubAppInstallation' + $installation.ID | Should -Not -BeNullOrEmpty + $installation.App | Should -BeOfType 'GitHubApp' + $installation.App.ClientID | Should -Be $githubApp.ClientID + $installation.App.AppID | Should -Not -BeNullOrEmpty + $installation.App.Slug | Should -Not -BeNullOrEmpty + $installation.Target | Should -BeOfType 'GitHubOwner' + $installation.Type | Should -Not -BeNullOrEmpty + $installation.RepositorySelection | Should -Not -BeNullOrEmpty + $installation.Permissions | Should -BeOfType 'PSCustomObject' + $installation.Events | Should -BeOfType 'string' + $installation.CreatedAt | Should -Not -BeNullOrEmpty + $installation.UpdatedAt | Should -Not -BeNullOrEmpty + $installation.SuspendedAt | Should -BeNullOrEmpty + $installation.SuspendedBy | Should -BeOfType 'GitHubUser' + } } It 'New-GitHubAppInstallationAccessToken - Can get app installation access tokens' { $installations = Get-GitHubAppInstallation - $installations | ForEach-Object { - $token = New-GitHubAppInstallationAccessToken -InstallationID $_.id - LogGroup 'Token' { - Write-Host ($token | Format-Table | Out-String) + LogGroup 'Tokens' { + $installations | ForEach-Object { + $token = New-GitHubAppInstallationAccessToken -InstallationID $_.id + Write-Host ($token | Format-List | Out-String) } $token | Should -Not -BeNullOrEmpty } diff --git a/tests/Variables.Tests.ps1 b/tests/Variables.Tests.ps1 index d6a3da75a..41107a50a 100644 --- a/tests/Variables.Tests.ps1 +++ b/tests/Variables.Tests.ps1 @@ -30,11 +30,17 @@ Describe 'Variables' { Context 'As using on ' -ForEach $authCases { BeforeAll { - $context = Connect-GitHubAccount @connectParams -PassThru -Silent + LogGroup 'Current Contexts' { + $context = Connect-GitHubAccount @connectParams -PassThru -Silent + Write-Host (Get-GitHubContext -ListAvailable | Format-List | Out-String) + } LogGroup 'Context' { Write-Host ($context | Format-List | Out-String) } if ($AuthType -eq 'APP') { + LogGroup 'Current Contexts' { + Write-Host (Get-GitHubContext -ListAvailable | Format-List | Out-String) + } LogGroup 'Context - Installation' { $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent Write-Host ($context | Format-List | Out-String)