Public/GitHub/New-GitHubCommit.ps1
|
function New-GitHubCommit { <# .SYNOPSIS Creates a commit on a GitHub repository branch via the GitHub API. .DESCRIPTION Uses the GitHub Git Data API to create a commit containing one or more file changes. Commits created via this method are automatically marked as Verified by GitHub, with no GPG or SSH signing key required. The Files parameter expects an array of hashtables each containing a 'Path' key (repo-root-relative, forward-slash separated) and a 'Content' key (raw file text). #> [CmdletBinding()] param ( # The GitHub token used to authenticate [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [Alias('GitHubToken', 'GitHubPAT')] [string] $Token, # The org/user that owns the repository [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [Alias('GitHubOrganisation', 'GitHubOrganization', 'GitHubOrg')] [string] $RepositoryOwner, # The repository name [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [Alias('RepoName')] [string] $RepositoryName, # The branch to commit to [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [string] $BranchName, # The commit message [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [string] $CommitMessage, # The files to include in the commit. Each hashtable must have 'Path' and 'Content' keys. [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [hashtable[]] $Files ) begin {} process { $Header = @{ Authorization = "token $Token" Accept = 'application/vnd.github.v3+json' } $BaseUri = "https://api.github.com/repos/$RepositoryOwner/$RepositoryName" try { # Resolve the current HEAD commit and its tree $Ref = Invoke-RestMethod ` -Uri "$BaseUri/git/ref/heads/$BranchName" ` -Headers $Header $HeadSHA = $Ref.object.sha $HeadCommit = Invoke-RestMethod ` -Uri "$BaseUri/git/commits/$HeadSHA" ` -Headers $Header $BaseTreeSHA = $HeadCommit.tree.sha # Create a blob for each file and collect tree entries $TreeItems = foreach ($File in $Files) { $BlobBody = @{ content = $File.Content encoding = 'utf-8' } | ConvertTo-Json $Blob = Invoke-RestMethod ` -Uri "$BaseUri/git/blobs" ` -Method Post ` -Headers $Header ` -Body $BlobBody @{ path = $File.Path mode = '100644' type = 'blob' sha = $Blob.sha } } # Build a new tree on top of the existing one $TreeBody = @{ base_tree = $BaseTreeSHA tree = @($TreeItems) } | ConvertTo-Json -Depth 5 $NewTree = Invoke-RestMethod ` -Uri "$BaseUri/git/trees" ` -Method Post ` -Headers $Header ` -Body $TreeBody # Create the commit object $CommitBody = @{ message = $CommitMessage tree = $NewTree.sha parents = @($HeadSHA) } | ConvertTo-Json $NewCommit = Invoke-RestMethod ` -Uri "$BaseUri/git/commits" ` -Method Post ` -Headers $Header ` -Body $CommitBody # Advance the branch ref to the new commit $UpdateRefBody = @{ sha = $NewCommit.sha force = $false } | ConvertTo-Json Invoke-RestMethod ` -Uri "$BaseUri/git/refs/heads/$BranchName" ` -Method Patch ` -Headers $Header ` -Body $UpdateRefBody | Out-Null } catch { throw "Failed to create commit on '$BranchName'.`n$($_.Exception.Message)" } } end { if ($NewCommit) { return $NewCommit } else { return $null } } } |