Skip to content
4 changes: 2 additions & 2 deletions Coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@
| `/repos/{owner}/{repo}/commits/{ref}/statuses` | | :x: | | | |
| `/repos/{owner}/{repo}/community/profile` | | :x: | | | |
| `/repos/{owner}/{repo}/compare/{basehead}` | | :x: | | | |
| `/repos/{owner}/{repo}/contents/{path}` | :x: | :x: | | | :x: |
| `/repos/{owner}/{repo}/contents/{path}` | :x: | :white_check_mark: | | | :x: |
| `/repos/{owner}/{repo}/contributors` | | :white_check_mark: | | | |
| `/repos/{owner}/{repo}/dependabot/alerts` | | :x: | | | |
| `/repos/{owner}/{repo}/dependabot/alerts/{alert_number}` | | :x: | :x: | | |
Expand Down Expand Up @@ -534,7 +534,7 @@
| `/repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/dismissals` | | | | | :x: |
| `/repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/events` | | | | :x: | |
| `/repos/{owner}/{repo}/pulls/{pull_number}/update-branch` | | | | | :x: |
| `/repos/{owner}/{repo}/readme` | | :x: | | | |
| `/repos/{owner}/{repo}/readme` | | :white_check_mark: | | | |
| `/repos/{owner}/{repo}/readme/{dir}` | | :x: | | | |
| `/repos/{owner}/{repo}/releases` | | :white_check_mark: | | :white_check_mark: | |
| `/repos/{owner}/{repo}/releases/assets/{asset_id}` | :white_check_mark: | :white_check_mark: | :white_check_mark: | | |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
function Get-GitHubRepositoryContent {
<#
.SYNOPSIS
Retrieves the contents of a file or directory from a GitHub repository.

.DESCRIPTION
This function calls the GitHub API endpoint that returns the contents of a repository.
You can specify a file or directory path using -Path. If you leave -Path empty,
the function will return the repository's root directory contents.

Optionally, you can supply a specific commit, branch, or tag via -Ref.
The function relies on the provided GitHub context for authentication and configuration.

.EXAMPLE
Get-GitHubRepositoryContent -Owner "octocat" -Repo "Hello-World" -Path "README.md" -Ref "main"

Output:
```powershell
{
"name": "README.md",
"path": "README.md",
"sha": "123abc456def",
"size": 1256,
"url": "https://api.github.com/repos/octocat/Hello-World/contents/README.md",
"type": "file"
}
```

Retrieves the README.md file from the main branch of the repository.

.OUTPUTS
System.Object

.NOTES
The response object containing details about the repository contents.

.LINK
https://psmodule.io/GitHub/Functions/Get-GitHubRepositoryContent/
#>
[CmdletBinding(SupportsShouldProcess)]
param(
# The GitHub account owner.
[Parameter(Mandatory)]
[Alias('Organization')]
[Alias('User')]
[string] $Owner,

# The name of the repository.
[Parameter(Mandatory)]
[string] $Repository,

# The file or directory path in the repository.
[Parameter()]
[string] $Path,

# Optional reference (commit, branch, or tag) to get content from.
[Parameter()]
[string] $Ref,

# The GitHub context for the API call.
[Parameter()]
[object] $Context = (Get-GitHubContext)
)

begin {
$stackPath = Get-PSCallStackPath
Write-Debug "[$stackPath] - Start"
$Context = Resolve-GitHubContext -Context $Context
Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
}

process {
# Build the query parameters (only ref is supported here).
$body = @{
ref = $Ref
}

# Prepare the input for the GitHub API call.
$inputObject = @{
Method = 'GET'
APIEndpoint = "/repos/$Owner/$Repository/contents/$Path"
Body = $body
Context = $Context
}

Invoke-GitHubAPI @inputObject | ForEach-Object {
Write-Output $_.Response
}
}

end {
Write-Debug "[$stackPath] - End"
}
}
50 changes: 50 additions & 0 deletions tests/GitHub.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,56 @@ Describe 'API' {
}
}
}
Context 'Repository' {
Context 'Content' {
BeforeEach {
Connect-GitHubApp -Organization 'psmodule-test-org' -Default
}
AfterEach {
Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount
}
It 'Get-GitHubRepositoryContent - retrieves README.md from main branch' {
$Owner = 'github'
$Repository = 'rest-api-description'
$Path = 'README.md'
$Ref = 'main'

$Result = Get-GitHubRepositoryContent -Owner $Owner -Repository $Repository -Path $Path -Ref $Ref

$Result | Should -Not -BeNullOrEmpty
$Result | Should -BeOfType 'System.Object'
$result | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ }
$Result.name | Should -Be 'README.md'
}
It 'Get-GitHubRepositoryContent - retrieves root directory contents' {
$Owner = 'github'
$Repository = 'rest-api-description'

$Result = Get-GitHubRepositoryContent -Owner $Owner -Repository $Repository
$result | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ }
$Result | Should -Not -BeNullOrEmpty
$Result | Should -BeOfType 'System.Object'
}
It 'Get-GitHubRepositoryContent - returns error for non-existent file' {
$Owner = 'github'
$Repository = 'rest-api-description'
$Path = 'nonexistentfile.md'

{ Get-GitHubRepositoryContent -Owner $Owner -Repository $Repository -Path $Path } | Should -Throw
}
It 'Get-GitHubRepositoryContent - retrieves content from a feature branch' {
$Owner = 'github'
$Repository = 'rest-api-description'
$Path = 'README.md'
$Ref = 'feature-branch'

$Result = Get-GitHubRepositoryContent -Owner $Owner -Repository $Repository -Path $Path -Ref $Ref
$result | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ }
$Result | Should -Not -BeNullOrEmpty
$Result | Should -BeOfType 'System.Object'
}
}
}
}

Describe 'Emojis' {
Expand Down
81 changes: 81 additions & 0 deletions tools/Get-GitHubAPIDescriptor.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
###
### List Top-Level Folders and Subdirectories in a GitHub Repository
###

# Define repository owner and name
$owner = 'github'
$Repository = 'rest-api-description'

# GitHub API URL for root contents
$rootUrl = "https://api.github.com/repos/$owner/$Repository/contents"

# Invoke the REST API to get root contents (add User-Agent header if needed)
$rootContents = Invoke-RestMethod -Uri $rootUrl -Headers @{ 'Accept' = 'application/vnd.github.v3+json' }
$rootContents | Format-Table -AutoSize

$rootContents | ForEach-Object {
[PSCustomObject]@{
Name = $_.name
Size = $_.size
Type = $_.type
}
} | Sort-Object Type, Name | Format-Table

# Filter for directories in the root (type equals "dir")
$topLevelFolders = $rootContents | Where-Object { $_.type -eq 'dir' } | Select-Object -ExpandProperty name

# Output the top-level folder names
$topLevelFolders


###
### List Subdirectories for Each Top Folder:
###

foreach ($folder in $topLevelFolders) {
Write-Host "`nSubfolders in '$folder':"
# Construct URL for the folder's contents
$folderUrl = "https://api.github.com/repos/$owner/$Repository/contents/$folder"
$folderContents = Invoke-RestMethod -Uri $folderUrl -Headers @{ 'Accept' = 'application/vnd.github.v3+json' }

# Filter for subdirectories (type "dir") within this folder
$subDirs = $folderContents | Where-Object { $_.type -eq 'dir' } | Select-Object -ExpandProperty name

# Print each subfolder name
$subDirs | ForEach-Object { Write-Host "- $_" }
}



# (Optional) Get entire tree recursively - may return a lot of data for large repos
$branch = 'main' # or specify default branch/commit SHA
$treeUrl = "https://api.github.com/repos/$owner/$Repository/git/trees/$branch`?recursive=1"
$treeData = Invoke-RestMethod -Uri $treeUrl -Headers @{ 'Accept' = 'application/vnd.github.v3+json' }

# $treeData.tree is a list of all paths in the repository (each with type "blob" for file or "tree" for folder).
# We can filter this list for type "tree" to get directories.
$allDirs = $treeData.tree | Where-Object { $_.type -eq 'tree' } | Select-Object -ExpandProperty path



function Get-GitHubAPIDescription {
<#
.SYNOPSIS
Retrieves the GitHub REST API description from the GitHub REST API description repository.

.DESCRIPTION
Retrieves the GitHub REST API description from the GitHub REST API description repository.
The API description is used to generate the GitHub REST API functions.

.EXAMPLE
Get-GitHubAPIDescription
#>

# GitHub REST API description repository
$APIDocURI = 'https://raw.githubusercontent.com/github/rest-api-description/main'
$Bundled = '/descriptions/api.github.com/api.github.com.json'
$APIDocURI = $APIDocURI + $Bundled
$response = Invoke-RestMethod -Uri $APIDocURI -Method Get

return $response
}
72 changes: 72 additions & 0 deletions tools/utilities/Get-GitHubAPIDescriptor.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
###
### List Top-Level Folders and Subdirectories in a GitHub Repository
###

# Define repository owner and name
$owner = 'github'
$repo = 'rest-api-description'

# GitHub API URL for root contents
$rootUrl = "https://api.github.com/repos/$owner/$repo/contents"

# Invoke the REST API to get root contents (add User-Agent header if needed)
$rootContents = Invoke-RestMethod -Uri $rootUrl -Headers @{ 'Accept' = 'application/vnd.github.v3+json' }

# Filter for directories in the root (type equals "dir")
$topLevelFolders = $rootContents | Where-Object { $_.type -eq 'dir' } | Select-Object -ExpandProperty name

# Output the top-level folder names
$topLevelFolders


###
### List Subdirectories for Each Top Folder:
###

foreach ($folder in $topLevelFolders) {
Write-Host "`nSubfolders in '$folder':"
# Construct URL for the folder's contents
$folderUrl = "https://api.github.com/repos/$owner/$repo/contents/$folder"
$folderContents = Invoke-RestMethod -Uri $folderUrl -Headers @{ 'Accept' = 'application/vnd.github.v3+json' }

# Filter for subdirectories (type "dir") within this folder
$subDirs = $folderContents | Where-Object { $_.type -eq 'dir' } | Select-Object -ExpandProperty name

# Print each subfolder name
$subDirs | ForEach-Object { Write-Host "- $_" }
}



# (Optional) Get entire tree recursively - may return a lot of data for large repos
$branch = 'main' # or specify default branch/commit SHA
$treeUrl = "https://api.github.com/repos/$owner/$repo/git/trees/$branch`?recursive=1"
$treeData = Invoke-RestMethod -Uri $treeUrl -Headers @{ 'Accept' = 'application/vnd.github.v3+json' }

# $treeData.tree is a list of all paths in the repository (each with type "blob" for file or "tree" for folder).
# We can filter this list for type "tree" to get directories.
$allDirs = $treeData.tree | Where-Object { $_.type -eq 'tree' } | Select-Object -ExpandProperty path



function Get-GitHubAPIDescription {
<#
.SYNOPSIS
Retrieves the GitHub REST API description from the GitHub REST API description repository.

.DESCRIPTION
Retrieves the GitHub REST API description from the GitHub REST API description repository.
The API description is used to generate the GitHub REST API functions.

.EXAMPLE
Get-GitHubAPIDescription
#>

# GitHub REST API description repository
$APIDocURI = 'https://raw.githubusercontent.com/github/rest-api-description/main'
$Bundled = '/descriptions/api.github.com/api.github.com.json'
$APIDocURI = $APIDocURI + $Bundled
$response = Invoke-RestMethod -Uri $APIDocURI -Method Get

return $response
}
49 changes: 12 additions & 37 deletions tools/utilities/New-FunctionTemplate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,53 +33,28 @@
Write-Debug "[$stackPath] - Start"
$Context = Resolve-GitHubContext -Context $Context
Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT

if ([string]::IsNullOrEmpty($Enterprise)) {
$Enterprise = $Context.Enterprise
}
Write-Debug "Enterprise : [$($Context.Enterprise)]"

if ([string]::IsNullOrEmpty($Owner)) {
$Owner = $Context.Owner
}
Write-Debug "Owner : [$($Context.Owner)]"

if ([string]::IsNullOrEmpty($Repo)) {
$Repo = $Context.Repo
}
Write-Debug "Repo : [$($Context.Repo)]"
}

process {
try {
$body = @{
per_page = $PerPage
}
$body = @{
per_page = $PerPage
}

$inputObject = @{
Context = $Context
APIEndpoint = "/orgs/$OrganizationName/blocks"
Method = 'GET'
Body = $body
}
$inputObject = @{
Method = 'GET'
APIEndpoint = "/orgs/$OrganizationName/blocks"
Body = $body
Context = $Context
}

if ($PSCmdlet.ShouldProcess('Target', 'Operation')) {
Invoke-GitHubAPI @inputObject | ForEach-Object {
Write-Output $_.Response
}
if ($PSCmdlet.ShouldProcess('Target', 'Operation')) {
Invoke-GitHubAPI @inputObject | ForEach-Object {
Write-Output $_.Response
}
} catch {
Write-Debug "Error: $_"
} finally {
Write-Debug 'Finally'
}
}

end {
Write-Debug "[$stackPath] - End"
}

clean {
Write-Debug 'Clean'
}
}