Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
653f4b1
Simplify the token refresh tech for UAT
MariusStorhaug Dec 5, 2024
70a0932
Get authed app or a specific app
MariusStorhaug Dec 5, 2024
2eafc9c
No bare URLs
MariusStorhaug Dec 5, 2024
31e936d
Fix
MariusStorhaug Dec 5, 2024
74c3f01
MOve some logic :)
MariusStorhaug Dec 6, 2024
663ea50
Check to see if we can make new names on IAT creds
MariusStorhaug Dec 6, 2024
674defd
Dont publish
MariusStorhaug Dec 6, 2024
74ecacd
Fix context
MariusStorhaug Dec 6, 2024
cccce9b
Fix typo in GitHub context test assertion
MariusStorhaug Dec 6, 2024
62f3be5
Change function to filter and update parameter attributes in Resolve-…
MariusStorhaug Dec 6, 2024
dcf5921
Add Connect-GitHubApp function for GitHub App authentication
MariusStorhaug Dec 6, 2024
5ea03d6
Add Assert-GitHubContext function to validate command context require…
MariusStorhaug Dec 6, 2024
f32ddf4
Add examples for GitHub user and app authentication in CallingAPIs.ps1
MariusStorhaug Dec 6, 2024
3ca0003
Fix argument completion and token selection
MariusStorhaug Dec 6, 2024
424e3ea
Add ClientID to authentication context in Connect-GitHubApp function
MariusStorhaug Dec 6, 2024
39b9fc1
Refactor parameter logging in Invoke-GitHubAPI function
MariusStorhaug Dec 6, 2024
5d91873
Change output type to pscustomobject and adjust default scope in Get-…
MariusStorhaug Dec 6, 2024
2ceeab4
Refactor GitHub context completion to use Name property for parameter…
MariusStorhaug Dec 6, 2024
4f917f3
Optimize installation retrieval in Connect-GitHubApp with parallel pr…
MariusStorhaug Dec 6, 2024
9855202
Improve debug output in Invoke-GitHubAPI by formatting parameters for…
MariusStorhaug Dec 6, 2024
2029994
Enhance debug output in Invoke-GitHubAPI to include parent function p…
MariusStorhaug Dec 6, 2024
8117936
Add InstallationID parameter to GitHub context and update related fun…
MariusStorhaug Dec 6, 2024
ad123fa
Refactor GitHub context format to use 'Name' property and update Conn…
MariusStorhaug Dec 6, 2024
441389c
Add InstallationID parameter to Set-GitHubContext for enhanced contex…
MariusStorhaug Dec 6, 2024
6437643
Adding a function in the resolver to return installations for targete…
MariusStorhaug Dec 6, 2024
86f99c0
Fix
MariusStorhaug Dec 6, 2024
3cf4a74
Refactor Resolve-GitHubContext to improve context validation and logging
MariusStorhaug Dec 6, 2024
8332079
Test
MariusStorhaug Dec 6, 2024
aa128c1
Add tests for connecting to GitHub App installations
MariusStorhaug Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions examples/CallingAPIs.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#region As a user: get the authenticated user
Connect-GitHub

# Simple example - output is the object
Get-GitHubUser

# More complex example - output is parts of the web response
Invoke-GitHubAPI -ApiEndpoint /user

# Most complex example - output is the entire web response
$context = Get-GitHubContext
Invoke-WebRequest -Uri "https://api.$($context.HostName)/user" -Token ($context.Token) -Authentication Bearer
#endregion


#region As an app: get the authenticated app
$ClientID = ''
$PrivateKey = ''
Connect-GitHub -ClientID $ClientID -PrivateKey $PrivateKey

# Simple example - output is the object
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-WebRequest -Uri "https://api.$($context.HostName)/user" -Token ($jwt.token) -Authentication Bearer
#endregion


#region As an app installation: get zen
Connect-GitHubApp -Installation 'PSModule'

# Simple example - output is the object
Get-GitHuben

# More complex example - output is parts of the web response
Invoke-GitHubAPI -ApiEndpoint /zen

# Most complex example - output is the entire web response
$context = Get-GitHubContext
Invoke-WebRequest -Uri "https://api.$($context.HostName)/zen" -Token ($context.Token) -Authentication Bearer
#endregion
7 changes: 7 additions & 0 deletions src/classes/public/GitHubContext.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
# github.com/Octocat
[string] $Name

# The context type
# User / App / Installation
[string] $Type

# The user name.
[string] $UserName

Expand Down Expand Up @@ -69,6 +73,9 @@
# 2024-01-01-00:00:00
[datetime] $TokenExpirationDate

# The installation ID.
[int] $InstallationID

# The refresh token.
[securestring] $RefreshToken

Expand Down
7 changes: 2 additions & 5 deletions src/completers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
$null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter

$contexts = Get-GitHubContext -ListAvailable -Verbose:$false | Where-Object { "$($_.HostName)/$($_.UserName)" -like "$wordToComplete*" }

$contexts | ForEach-Object {
$contextID = "$($_.HostName)/$($_.UserName)"
[System.Management.Automation.CompletionResult]::new($contextID, $contextID, 'ParameterValue', $contextID)
Get-GitHubContext -ListAvailable -Verbose:$false | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, 'ParameterValue', $_.Name)
}
}
22 changes: 2 additions & 20 deletions src/formats/GitHubContext.Format.ps1xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>UserName</Label>
</TableColumnHeader>
<TableColumnHeader>
<Label>HostName</Label>
<Label>Name</Label>
</TableColumnHeader>
<TableColumnHeader>
<Label>AuthType</Label>
Expand All @@ -24,21 +21,12 @@
<TableColumnHeader>
<Label>TokenExpirationDate</Label>
</TableColumnHeader>
<TableColumnHeader>
<Label>Owner</Label>
</TableColumnHeader>
<TableColumnHeader>
<Label>Repo</Label>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>UserName</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>HostName</PropertyName>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>AuthType</PropertyName>
Expand All @@ -49,12 +37,6 @@
<TableColumnItem>
<PropertyName>TokenExpirationDate</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Owner</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Repo</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
Expand Down
44 changes: 44 additions & 0 deletions src/functions/private/Apps/Get-GitHubAppByName.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
filter Get-GitHubAppByName {
<#
.SYNOPSIS
Get an app

.DESCRIPTION
Gets a single GitHub App using the app's slug.

.EXAMPLE
Get-GitHubAppByName -AppSlug 'github-actions'

Gets the GitHub App with the slug 'github-actions'.

.NOTES
[Get an app](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-an-app)
#>
[OutputType([pscustomobject])]
[CmdletBinding()]
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., https://github.com/settings/apps/<app_slug>).
# Example: 'github-actions'
[Parameter(Mandatory)]
[Alias('Name')]
[string] $AppSlug,

# 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 = (Get-GitHubContext)
)

$Context = Resolve-GitHubContext -Context $Context

$inputObject = @{
Context = $Context
APIEndpoint = "/apps/$AppSlug"
Method = 'GET'
}

Invoke-GitHubAPI @inputObject | ForEach-Object {
Write-Output $_.Response
}
}
43 changes: 43 additions & 0 deletions src/functions/private/Apps/Get-GitHubAuthenticatedApp.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
filter Get-GitHubAuthenticatedApp {
<#
.SYNOPSIS
Get the authenticated app

.DESCRIPTION
Returns the GitHub App associated with the authentication credentials used. To see how many app installations are associated with this
GitHub App, see the `installations_count` in the response. For more details about your app's installations, see the
"[List installations for the authenticated app](https://docs.github.com/rest/apps/apps#list-installations-for-the-authenticated-app)"
endpoint.

You must use a [JWT](https://docs.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-a-github-app)
to access this endpoint.

.EXAMPLE
Get-GitHubAuthenticatedApp

Get the authenticated app.

.NOTES
[Get the authenticated app](https://docs.github.com/rest/apps/apps#get-an-app)
#>
[OutputType([pscustomobject])]
[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()]
[object] $Context = (Get-GitHubContext)
)

$Context = Resolve-GitHubContext -Context $Context

$inputObject = @{
Context = $Context
APIEndpoint = '/app'
Method = 'GET'
}

Invoke-GitHubAPI @inputObject | ForEach-Object {
Write-Output $_.Response
}
}
52 changes: 36 additions & 16 deletions src/functions/private/Auth/Context/Resolve-GitHubContext.ps1
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
function Resolve-GitHubContext {
filter Resolve-GitHubContext {
<#
.SYNOPSIS
Resolves the context into a GitHubContext object.

.DESCRIPTION
This function resolves the context into a GitHubContext object.
It can take both the
If the context is already a GitHubContext object, it will return the object.
If the context is a string, it will get the context details and return a GitHubContext object.

If the context is a App, it will look at the available contexts and return the one that matches the scope of the command being run.

.EXAMPLE
$Context = Resolve-GitHubContext -Context 'github.com/Octocat'
Expand All @@ -22,27 +25,44 @@
param(
# The context to resolve into an object. Used to get the details for the API call.
# Can be either a string or a GitHubContext object.
[Parameter()]
[Parameter(ValueFromPipeline)]
[object] $Context = (Get-GitHubContext)
)

if ($Context -is [GitHubContext]) {
return $Context
begin {
$commandName = $MyInvocation.MyCommand.Name
Write-Verbose "[$commandName] - Start"
Write-Verbose 'Context:'
$Context | Out-String -Stream | ForEach-Object { Write-Verbose $_ }
}

if ([string]::IsNullOrEmpty($Context)) {
throw "No contexts has been specified. Please provide a context or log in using 'Connect-GitHub'."
}
process {
if ($Context -is [string]) {
$contextName = $Context
Write-Debug "Getting context: [$contextName]"
$Context = Get-GitHubContext -Context $contextName
}

if ($Context -is [string]) {
$contextName = $Context
Write-Debug "Getting context: [$contextName]"
$Context = Get-GitHubContext -Context $contextName
}
if (-not $Context) {
throw "Context [$contextName] not found. Please provide a valid context or log in using 'Connect-GitHub'."
}

if (-not $Context) {
throw "Context [$contextName] not found. Please provide a valid context or log in using 'Connect-GitHub'."
switch ($Context.Type) {
'App' {
$availableContexts = Get-GitHubContext -ListAvailable |
Where-Object { $_.Type -eq 'Installation' -and $_.ClientID -eq $Context.ClientID }
$params = Get-FunctionParameter -Scope 2
Write-Verbose 'Resolving parameters used in called function'
Write-Verbose ($params | Out-String)
if ($params.Keys -in 'Owner', 'Organization') {
$Context = $availableContexts | Where-Object { $_.Owner -eq $params.Owner }
}
}
}
}

return $Context
end {
Write-Verbose "[$commandName] - End"
Write-Output $Context
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
function Get-FunctionParameter {
<#
.SYNOPSIS
Get the parameters and their final value in a function.

.DESCRIPTION
This function retrieves the parameters and their final value in a function.
If a parameter is provided, it will retrieve the provided value.
If a parameter is not provided, it will attempt to retrieve the default value.

.EXAMPLE
Get-FunctionParameter

This will return all the parameters and their final value in the current function.

.EXAMPLE
Get-FunctionParameter -IncludeCommonParameters

This will return all the parameters and their final value in the current function, including common parameters.

.EXAMPLE
Get-FunctionParameter -Scope 2

This will return all the parameters and their final value in the grandparent function.
#>
[OutputType([pscustomobject])]
[CmdletBinding()]
param(
# Include common parameters in the output.
[Parameter()]
[switch] $IncludeCommonParameters,

# The function to get the parameters for.
# Default is the calling scope (0).
# Scopes are based on nesting levels:
# 0 - Current scope
# 1 - Parent scope
# 2 - Grandparent scope
[Parameter()]
[int] $Scope = 0
)

$Scope++

$commonParameters = @(
'ProgressAction', 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable',
'OutVariable', 'OutBuffer', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable', 'WhatIf',
'Confirm'
)

$InvocationInfo = (Get-Variable -Name MyInvocation -Scope $Scope -ErrorAction Stop).Value
$boundParameters = $InvocationInfo.BoundParameters
$allParameters = @{}
$parameters = $InvocationInfo.MyCommand.Parameters

foreach ($paramName in $parameters.Keys) {
if (-not $IncludeCommonParameters -and $paramName -in $commonParameters) {
continue
}
if ($boundParameters.ContainsKey($paramName)) {
# Use the explicitly provided value
$allParameters[$paramName] = $boundParameters[$paramName]
} else {
# Attempt to retrieve the default value by invoking it
try {
$defaultValue = (Get-Variable -Name $paramName -Scope $Scope -ErrorAction SilentlyContinue).Value
} catch {
$defaultValue = $null
}
$allParameters[$paramName] = $defaultValue
}
}

[pscustomobject]$allParameters
}
Loading