Extending the GitHub CLI
I know I've mentioned the GitHub command line tool, gh.exe
, in the past. This is a great tool for working with GitHub repositories from the command line. I use it all the time and have built some automation around it. You can install it with winget or other package managers.
winget Install github.cli
Or you can download directly from https://cli.github.com/. This is also where you can find the documentation.
I bring this up because the other day I discovered a new feature of gh.exe
that I didn't know about. You can extend the functionality of gh.exe
with extensions. You can think of an extension as a plug-in. The extension does just what the name implies, it extends the functionality of gh.exe
.
Extensions are written in a number of languages like Go, Rust, and Python. The extensions use the GitHub API to achieve an end result. You don't have to worry about the language the extension is written in. You just install the extension that meets your need and use it.
Finding Extensions
You can use gh.exe
to search for extensions.
PS C:\> gh extension search --help
Usage: gh extension search [<query>] [flags]
Flags:
-q, --jq expression Filter JSON output using a jq expression
--json fields Output JSON with the specified fields
--license strings Filter based on license type
-L, --limit int Maximum number of extensions to fetch (default 30)
--order string Order of repositories returned, ignored unless '--sort' flag is specified: {asc|desc} (default "desc")
--owner strings Filter on owner
--sort string Sort fetched repositories: {forks|help-wanted-issues|stars|updated} (default "best-match")
-t, --template string Format JSON output using a Go template; see "gh help formatting"
-w, --web Open the search query in the web browser
Or maybe you want to search for a topic or key word.
Some of the gh.exe
parameters provide a formatting option which allows you to the output as JSON. When it comes to searching extensions you can use any of these JSON field.
createdAt
defaultBranch
description
forksCount
fullName
hasDownloads
hasIssues
hasPages
hasProjects
hasWiki
homepage
id
isArchived
isDisabled
isFork
isPrivate
language
license
name
openIssuesCount
owner
pushedAt
size
stargazersCount
updatedAt
url
visibility
watchersCount
The field name is case-sensitive, and specify them as a comma-separated list.
PS C:\> gh extension search branch --sort updated --json fullName,url,updatedAt,description --limit 1
[
{
"description": "A gh extension to create a branch out of issue",
"fullName": "chmouel/gh-workon",
"updatedAt": "2024-12-16T09:25:39Z",
"url": "https://github.com/chmouel/gh-workon"
}
]
Of course, once you have JSON, you can create objects you can work with in PowerShell.
gh extension search branch --sort updated --json fullName,url,updatedAt,description |
ConvertFrom-Json |
ForEach-Object {
[PSCustomObject]@{
PSTypeName = 'ghExtensionSearchResult'
Name = $_.fullName
Updated = $_.updatedAt
Url = $_.url
Description = $_.description
}
} | Sort Updated -Descending
> ⚠ Warning > If the description includes emojis, the emoji won't be displayed properly
It wouldn't take much to turn this into a function that you could use to search for extensions.
Even though I'm sorting in the initial gh.exe
command, the sort doesn't appear to be correct so I am sorting again after I create the custom object. I'm creating a custom object so that I can define a typename and provide more meaningful property names.
If you prefer, you can open the search results in a browser.
gh extension search -w
This will open a page on GitHub.com additional filtering options. But my favorite way to search is to use the browse option.
gh extension browse
This will open a terminal user interface (TUI) where you can browse and search for extensions.
You can use j
and k
to move up and down the list or the arrow keys. The extension's README file is displayed on the right. If you find an extension you want to know more about, press w
which will open the extension's GitHub project page in your browser. This is a great way to view the complete README file and any other information the author has provided.
If you want to filter, press /
and type a search term in the filter box.
When you are finished browsing, press q
to quit.
Installing Extensions
If you are browsing, you can easily install an extension by pressing i
. Otherwise, install the extension with the full name
gh extension install joaom00/gh-b
If you are building PowerShell tools, you need to specify the extension using the
format.
Upgrading Extensions
Over time, extensions, like any software, will be updated. I have not been using extensions long enough to know if there is any sort of notification process. You can check for updates with the gh extension list
command.
You can upgrade an extension by name.
gh extension upgrade gh-b
Or you can upgrade all extensions.
PS C:\> gh extension upgrade --all
[b]: already up to date
[dash]: already up to date
[markdown-preview]: already up to date
[userfetch]: already up to date
✓ Successfully checked extension upgrades
Removing Extensions
If you no longer need an extension, you can remove it.
PS C:\> gh extension remove markdown-Preview
✓ Removed extension markdown-Preview
If you are browsing, you can remove an extension by pressing r
.
Listing Extensions
You can list all installed extensions from a command prompt.
PS C:\> gh extension list
NAME REPO VERSION
gh b joaom00/gh-b v0.2.3
gh dash dlvhdr/gh-dash v4.7.3
gh userfetch sheepla/gh-userfetch 9c90b188
This is text output. Unfortunately, the list
option doesn't support JSON formatting and there's no more information you can get here.
However, this is where PowerShell comes to the rescue. I wrote a quick function to list installed gh.exe
extensions.
Function Get-GHInstalledExtension {
[CmdletBinding()]
[OutputType('ghExtension')]
Param()
$data = gh extension list
if ($data) {
foreach ($item in $data) {
$split = $item.Split()
$fullName = $split[2]
#get details from search
#JSON fields are case-sensitive
$detail = gh extension search $fullName --json description,url,updatedAt,size,stargazersCount |
ConvertFrom-Json
#Create a custom typed object
[PSCustomObject]@{
PSTypeName = 'ghExtension'
FullName = $fullName
Owner = $fullName.Split('/')[0]
Name = $split[1]
URL = $detail.url
Description = $detail.description
Updated = $detail.updatedAt
Size = $detail.size
Stars = $detail.stargazersCount
Version = $split[3]
}
}
}
else {
Write-Warning 'No gh extensions installed.'
}
}
The function parses the string output from gh extension list
and then uses the gh extension search
command to get more details about the extension. The function returns a custom object with the details.
I have yet to find a good way to preserve emojis in the description.
Using Extensions
To use the extension, you can invoke it with its short name.
gh userfetch
Some extensions might have help or usage information.
PS C:\> gh dash --help
A gh extension that shows a configurable dashboard of pull requests and issues.
Usage:
gh dash [flags]
Flags:
-c, --config string use this configuration file (default is $GH_DASH_CONFIG, or if not set,
$XDG_CONFIG_HOME/gh-dash/config.yml)
--debug passing this flag will allow writing debug output to debug.log
-h, --help help for gh-dash
-v, --version version for gh
Otherwise, you'll need to check the extension's GitHub project page for more information.
Summary
There are over 500 extensions available for gh.exe
. I have found a few that I think will be useful. I'd love to hear what extensions you find useful. I'd also love to hear how you build PowerShell tooling around them.