Skip to content

Commit 329ef75

Browse files
[Feature] Users - Get public and private (for authenticated user) info about a user (#28)
- `Invoke-GitHubAPI.ps1` updates: - `Get-GitHubRelease` to support `Accept` header - Added funtionality to convert body to query parameters when run as a `GET` request. - Improve error handling. - `Connect-GitHubAccount` updates: - Added support for setting default `Owner` and `Repository` for `Invoke-GitHubAPI` calls. - `Get-GitHubConfig` updates: - Added support for returning all settings as a hashtable. - API call functions: - Multiple new commands available, among other some user functions (Fixes #13) - Update the way outputs are "streamed" to the pipeline.
1 parent 0f681fc commit 329ef75

39 files changed

+1210
-66
lines changed

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# GitHub Powershell Module
2-
31
# GitHub PowerShell
42

53
The **GitHub PowerShell** module serves as a convenient API wrapper around [GitHub's REST API](https://docs.github.com/en/rest), making the functionalities and data available on GitHub accessible through PowerShell commands. This module is tailored for developers, administrators, and GitHub enthusiasts who are familiar with PowerShell and want to integrate or manage their GitHub repositories seamlessly.

src/GitHub/GitHub.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
$scriptFilePath = $MyInvocation.MyCommand.Path
22

3-
Write-Verbose "[$scriptFilePath] - Initializing GitHub module..." -Verbose
3+
Write-Verbose "[$scriptFilePath] - Initializing GitHub module..."
44

55
Initialize-SecretVault -Name $script:SecretVault.Name -Type $script:SecretVault.Type
66

src/GitHub/GitHub.psd1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Author = 'Marius Storhaug'
44

55
# Version number of this module
6-
ModuleVersion = '0.0.1'
6+
ModuleVersion = '0.1.1'
77

88
# Description of the functionality provided by this module
99
Description = 'GitHub PowerShell Module'
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function Invoke-DrawMenu {
2+
## supportfunction to the Menu function below
3+
param (
4+
$menuItems,
5+
$menuPosition,
6+
$menuTitel
7+
)
8+
$fcolor = $host.UI.RawUI.ForegroundColor
9+
$bcolor = $host.UI.RawUI.BackgroundColor
10+
$l = $menuItems.length + 1
11+
Clear-Host
12+
$menuwidth = $menuTitel.length + 4
13+
Write-Host "`t" -NoNewline
14+
Write-Host ('*' * $menuwidth) -fore $fcolor -back $bcolor
15+
Write-Host "`t" -NoNewline
16+
Write-Host "* $menuTitel *" -fore $fcolor -back $bcolor
17+
Write-Host "`t" -NoNewline
18+
Write-Host ('*' * $menuwidth) -fore $fcolor -back $bcolor
19+
Write-Host ''
20+
Write-Debug "L: $l MenuItems: $menuItems MenuPosition: $menuposition"
21+
for ($i = 0; $i -le $l; $i++) {
22+
Write-Host "`t" -NoNewline
23+
if ($i -eq $menuPosition) {
24+
Write-Host "$($menuItems[$i])" -fore $bcolor -back $fcolor
25+
} else {
26+
Write-Host "$($menuItems[$i])" -fore $fcolor -back $bcolor
27+
}
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function Menu {
2+
## Generate a small "DOS-like" menu.
3+
## Choose a menuitem using up and down arrows, select by pressing ENTER
4+
param (
5+
[array]$menuItems,
6+
$menuTitel = 'MENU'
7+
)
8+
$vkeycode = 0
9+
$pos = 0
10+
Invoke-DrawMenu $menuItems $pos $menuTitel
11+
while ($vkeycode -ne 13) {
12+
$press = $host.ui.rawui.readkey('NoEcho,IncludeKeyDown')
13+
$vkeycode = $press.virtualkeycode
14+
Write-Host "$($press.character)" -NoNewline
15+
if ($vkeycode -eq 38) { $pos-- }
16+
if ($vkeycode -eq 40) { $pos++ }
17+
if ($pos -lt 0) { $pos = 0 }
18+
if ($pos -ge $menuItems.length) { $pos = $menuItems.length - 1 }
19+
Invoke-DrawMenu $menuItems $pos $menuTitel
20+
}
21+
Write-Output $($menuItems[$pos])
22+
}
23+
24+
25+
<#
26+
? What account do you want to log into? [Use arrows to move, type to filter]
27+
> GitHub.com
28+
GitHub Enterprise Server
29+
#>

src/GitHub/public/API/Invoke-GitHubAPI.ps1

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
function Invoke-GitHubAPI {
22
<#
3-
.SYNOPSIS
4-
Calls the GitHub API using the provided parameters.
3+
.SYNOPSIS
4+
Calls the GitHub API using the provided parameters.
55
6-
.DESCRIPTION
7-
This function is a wrapper around Invoke-RestMethod tailored for calling GitHub's API.
8-
It automatically handles the endpoint URI construction, headers, and token authentication.
6+
.DESCRIPTION
7+
This function is a wrapper around Invoke-RestMethod tailored for calling GitHub's API.
8+
It automatically handles the endpoint URI construction, headers, and token authentication.
99
10-
.EXAMPLE
11-
Invoke-GitHubAPI -ApiEndpoint '/repos/user/repo/pulls' -Method GET
10+
.EXAMPLE
11+
Invoke-GitHubAPI -ApiEndpoint '/repos/user/repo/pulls' -Method GET
1212
13-
Gets all open pull requests for the specified repository.
13+
Gets all open pull requests for the specified repository.
1414
15-
.EXAMPLE
16-
Invoke-GitHubAPI -ApiEndpoint '/repos/user/repo/pulls' -Method GET -Body @{ state = 'open' }
15+
.EXAMPLE
16+
Invoke-GitHubAPI -ApiEndpoint '/repos/user/repo/pulls' -Method GET -Body @{ state = 'open' }
1717
18-
Gets all open pull requests for the specified repository, filtered by the 'state' parameter.
18+
Gets all open pull requests for the specified repository, filtered by the 'state' parameter.
1919
20-
.EXAMPLE
21-
Invoke-GitHubAPI -ApiEndpoint '/repos/user/repo/pulls' -Method GET -Body @{ state = 'open' } -Accept 'application/vnd.github.v3+json'
20+
.EXAMPLE
21+
Invoke-GitHubAPI -ApiEndpoint '/repos/user/repo/pulls' -Method GET -Body @{ state = 'open' } -Accept 'application/vnd.github.v3+json'
2222
23-
Gets all open pull requests for the specified repository, filtered by the 'state' parameter, and using the specified 'Accept' header.
24-
#>
23+
Gets all open pull requests for the specified repository, filtered by the 'state' parameter, and using the specified 'Accept' header.
24+
#>
2525
[CmdletBinding()]
2626
param (
2727
# The HTTP method to be used for the API request. It can be one of the following: GET, POST, PUT, DELETE, or PATCH.
@@ -42,15 +42,15 @@
4242

4343
# The 'Accept' header for the API request. If not provided, the default will be used by GitHub's API.
4444
[Parameter()]
45-
[string] $Accept,
45+
[string] $Accept = 'application/vnd.github+json',
4646

4747
# Specifies the HTTP version used for the request.
4848
[Parameter()]
49-
$HttpVersion = '2.0',
49+
[version] $HttpVersion = '2.0',
5050

5151
# Support Pagination Relation Links per RFC5988.
5252
[Parameter()]
53-
$FollowRelLink = $true,
53+
[bool] $FollowRelLink = $true,
5454

5555
# The secure token used for authentication in the GitHub API. It should be stored as a SecureString to ensure it's kept safe in memory.
5656
[Parameter()]
@@ -76,6 +76,23 @@
7676

7777
$URI = ("$ApiBaseUri/" -replace '/$', '') + ("/$ApiEndpoint" -replace '^/', '')
7878

79+
# $AccessTokenAsPlainText = ConvertFrom-SecureString $AccessToken -AsPlainText
80+
# # Swap out this by using the -Authentication Bearer -Token $AccessToken
81+
# switch -Regex ($AccessTokenAsPlainText) {
82+
# '^ghp_|^github_pat_' {
83+
# $headers.authorization = "token $AccessTokenAsPlainText"
84+
# }
85+
# '^ghu_|^gho_' {
86+
# $headers.authorization = "Bearer $AccessTokenAsPlainText"
87+
# }
88+
# default {
89+
# $tokenPrefix = $AccessTokenAsPlainText -replace '_.*$', '_*'
90+
# $errorMessage = "Unexpected AccessToken format: $tokenPrefix"
91+
# Write-Error $errorMessage
92+
# throw $errorMessage
93+
# }
94+
# }
95+
7996
$APICall = @{
8097
Uri = $URI
8198
Method = $Method
@@ -88,9 +105,19 @@
88105
StatusCodeVariable = 'StatusCode'
89106
ResponseHeadersVariable = 'ResponseHeaders'
90107
}
91-
Remove-HashTableEntries -Hashtable $APICall -NullOrEmptyValues
108+
$APICall | Remove-HashTableEntries -NullOrEmptyValues
92109

93110
if ($Body) {
111+
$Body | Remove-HashTableEntries -NullOrEmptyValues
112+
113+
# Use body to create the query string for GET requests
114+
if ($Method -eq 'GET') {
115+
$queryParams = ($Body.GetEnumerator() |
116+
ForEach-Object { "$([System.Web.HttpUtility]::UrlEncode($_.Key))=$([System.Web.HttpUtility]::UrlEncode($_.Value))" }) -join '&'
117+
if ($queryParams) {
118+
$APICall.Uri = $APICall.Uri + '?' + $queryParams
119+
}
120+
}
94121
if ($Body -is [string]) {
95122
$APICall.Body = $Body
96123
} else {
@@ -101,12 +128,11 @@
101128
try {
102129
Invoke-RestMethod @APICall | Write-Output
103130
Write-Verbose ($StatusCode | ConvertTo-Json -Depth 100)
104-
Write-Verbose ($ResponseHeaders | ConvertTo-Json -Depth 100)
105-
} catch [System.Net.WebException] {
106-
Write-Error "[$functionName] - WebException - $($_.Exception.Message)"
107-
throw $_
131+
Write-Verbose ($responseHeaders | ConvertTo-Json -Depth 100)
108132
} catch {
109-
Write-Error "[$functionName] - GeneralException - $($_.Exception.Message)"
110-
throw $_
133+
Write-Error "[$functionName] - Status code - [$StatusCode]"
134+
$err = $_ | ConvertFrom-Json -Depth 10
135+
Write-Error "[$functionName] - $($err.Message)"
136+
Write-Error "[$functionName] - For more info please see: [$($err.documentation_url)]"
111137
}
112138
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Function Disable-GitHubWorkflow {
2+
<#
3+
.NOTES
4+
https://docs.github.com/en/rest/reference/actions#disable-a-workflow
5+
#>
6+
[CmdletBinding()]
7+
param (
8+
[Parameter()]
9+
[string] $Owner = (Get-GitHubConfig -Name Owner),
10+
11+
[Parameter()]
12+
[string] $Repo = (Get-GitHubConfig -Name Repo),
13+
14+
[Parameter(
15+
Mandatory,
16+
ValueFromPipelineByPropertyName
17+
)]
18+
[string[]] $ID
19+
)
20+
21+
begin {}
22+
23+
process {
24+
$inputObject = @{
25+
APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/disable"
26+
Method = 'PUT'
27+
}
28+
29+
Invoke-GitHubAPI @inputObject | Out-Null
30+
31+
}
32+
33+
end {}
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Function Enable-GitHubWorkflow {
2+
<#
3+
.NOTES
4+
https://docs.github.com/en/rest/reference/actions#enable-a-workflow
5+
#>
6+
[CmdletBinding()]
7+
param (
8+
[Parameter()]
9+
[string] $Owner = (Get-GitHubConfig -Name Owner),
10+
11+
[Parameter()]
12+
[string] $Repo = (Get-GitHubConfig -Name Repo),
13+
14+
[Parameter(
15+
Mandatory,
16+
ValueFromPipelineByPropertyName
17+
)]
18+
[string[]] $ID
19+
)
20+
21+
begin {}
22+
23+
process {
24+
$inputObject = @{
25+
APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/enable"
26+
Method = 'PUT'
27+
}
28+
29+
Invoke-GitHubAPI @inputObject | Out-Null
30+
31+
}
32+
33+
end {}
34+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
function Get-GitHubWorkflow {
2+
<#
3+
.SYNOPSIS
4+
Lists the workflows in a repository.
5+
6+
.DESCRIPTION
7+
Anyone with read access to the repository can use this endpoint.
8+
If the repository is private you must use an access token with the repo scope.
9+
GitHub Apps must have the actions:read permission to use this endpoint.
10+
11+
.EXAMPLE
12+
Get-GitHubWorkflow -Owner 'octocat' -Repo 'hello-world'
13+
14+
Gets all workflows in the 'octocat/hello-world' repository.
15+
16+
.EXAMPLE
17+
Get-GitHubWorkflow -Owner 'octocat' -Repo 'hello-world' -Name 'hello-world.yml'
18+
19+
Gets the 'hello-world.yml' workflow in the 'octocat/hello-world' repository.
20+
21+
.NOTES
22+
https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#list-repository-workflows
23+
#>
24+
[CmdletBinding(DefaultParameterSetName = 'ByName')]
25+
param (
26+
[Parameter()]
27+
[string] $Owner = (Get-GitHubConfig -Name Owner),
28+
29+
[Parameter()]
30+
[string] $Repo = (Get-GitHubConfig -Name Repo),
31+
32+
[Parameter(ParameterSetName = 'ByName')]
33+
[string] $Name,
34+
35+
[Parameter(ParameterSetName = 'ByID')]
36+
[string] $ID,
37+
38+
[Parameter()]
39+
[int] $PerPage = 100
40+
)
41+
42+
begin {}
43+
44+
process {
45+
46+
$body = @{
47+
per_page = $PerPage
48+
}
49+
50+
$inputObject = @{
51+
APIEndpoint = "/repos/$Owner/$Repo/actions/workflows"
52+
Method = 'GET'
53+
Body = $body
54+
}
55+
56+
Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty workflows | Write-Output
57+
58+
}
59+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
Function Get-GitHubWorkflowRun {
2+
<#
3+
.NOTES
4+
https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-workflow
5+
https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository
6+
#>
7+
[CmdletBinding(DefaultParameterSetName = 'Repo')]
8+
param (
9+
[Parameter()]
10+
[string] $Owner = (Get-GitHubConfig -Name Owner),
11+
12+
[Parameter()]
13+
[string] $Repo = (Get-GitHubConfig -Name Repo),
14+
15+
[Parameter(ParameterSetName = 'ByName')]
16+
[string] $Name,
17+
18+
[Parameter(ParameterSetName = 'ByID')]
19+
[string] $ID,
20+
21+
[Parameter()]
22+
[int] $PerPage = 100
23+
)
24+
25+
begin {}
26+
27+
process {
28+
29+
$body = @{
30+
per_page = $PerPage
31+
}
32+
33+
if ($Name) {
34+
$ID = (Get-GitHubWorkflow -Owner $Owner -Repo $Repo -Name $Name).id
35+
}
36+
37+
if ($ID) {
38+
$Uri = "/repos/$Owner/$Repo/actions/workflows/$ID/runs"
39+
} else {
40+
$Uri = "/repos/$Owner/$Repo/actions/runs"
41+
}
42+
43+
$inputObject = @{
44+
APIEndpoint = $Uri
45+
Method = 'GET'
46+
Body = $body
47+
}
48+
49+
Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty workflow_runs | Write-Output
50+
51+
}
52+
53+
end {}
54+
55+
}

0 commit comments

Comments
 (0)