UMN-Github.psm1

###
# Copyright 2017 University of Minnesota, Office of Information Technology

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <http://www.gnu.org/licenses/>.

###########################
#
# Module for interacting with on premise gitHub service.
# Module is designed to work with both public and private(Enterprise) github APIv3 over https ONLY
# https://developer.github.com/enterprise/2.8/v3/
#
###########################

#region New-GitHubHeader
function New-GitHubHeader {
    <#
        .SYNOPSIS
            Create Header to be consumed by all other functions

        .DESCRIPTION
            Create Header to be consumed by all other functions

        .PARAMETER psCreds
            PScredential composed of your username/password to Git Server

        .PARAMETER authToken
            Use instead of user/pass, personal auth token

        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE

    #>

    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory,ParameterSetName='creds')]
        [System.Management.Automation.PSCredential]$psCreds,

        [Parameter(Mandatory,ParameterSetName='token')]
        [string]$authToken
    )

    if ($authToken){return (@{"Authorization" = "token $authToken"})}
    else{
        $auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($psCreds.UserName+':'+$psCreds.GetNetworkCredential().Password))    
        return (@{"Authorization" = "Basic $auth"})
    }
}
#endregion

#region Get-GitHubBase
function Get-GitHubBase {
    <#
        .SYNOPSIS
            Base for constructing Get commands

        .DESCRIPTION
            Base for constructing Get commands

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER sha
            sha for the commit, use Get-GitHubRepoRef to get it

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.


        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE
            Get-GitHubCommit -Username "Test" -Password "pass" -Repo "MyFakeReop" -Org "MyFakeOrg" -server "onPremiseServer" -sha $sha

    #>

    [CmdletBinding()]
    param(
        
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$data,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$org/$Repo/git/$data"
    try{return(Invoke-RestMethod -Method Get -Uri $URI -Headers $Headers)}
    catch{throw $Error[0]}
}
#endregion

#region Get-GitHubCommit
function Get-GitHubCommit {
    <#
        .SYNOPSIS
            Get a specific commit for a specific repo

        .DESCRIPTION
            Get a specific commit for a specific repo

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER sha
            sha for the commit, use Get-GitHubRepoRef to get it

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.


        .NOTES
            Name: Get-GitHubCommit
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE
            Get-GitHubCommit -Username "Test" -Password "pass" -Repo "MyFakeReop" -Org "MyFakeOrg" -server "onPremiseServer" -sha $sha

    #>

    [CmdletBinding()]
    param(
        
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$sha,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )
    Get-GitHubBase -headers $headers -Repo $Repo -Org $Org -server $server -data "commits/$sha"
}
#endregion

#region Get-GitHubRepoRef
function Get-GitHubRepoRef {
    <#
        .SYNOPSIS
            Get a specific reference or all references for a specific repo

        .DESCRIPTION
            Get a specific reference or all references for a specific repo, use -ref for a specific reference

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER ref
            Specific ref, run the command without it to get a list example would be.

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.


        .NOTES
            Name: Get-GitHubRepoRefs
            Author: Travis Sobeck
            LASTEDIT: 4/26/2017

        .EXAMPLE
            Get-GitHubRepoRefs -Username "Test" -Password "pass" -Repo "MyFakeReop" -Org "MyFakeOrg" -server "onPremiseServer"

        .EXAMPLE
            Get-GitHubRepoRefs -Username "Test" -Password "pass" -Repo "MyFakeReop" -Org "MyFakeOrg" -server "onPremiseServer" -ref 'refs/heads/master'

    #>

    [CmdletBinding()]
    [Alias("Get-GitHubRepoRefs")]
    param(
        
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [string]$ref,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if (-not($ref)){$ref = 'refs'}
    Get-GitHubBase -headers $headers -Repo $Repo -Org $Org -server $server -data $ref
}
#endregion

#region Get-GitHubRepoFile
function Get-GitHubRepoFile {
    <#
        .SYNOPSIS
            Get a file from a GitHub Repo.

        .DESCRIPTION
            Takes in a username, password, filename, repository, organization and a file to output to then downloads the file
            from the repository.

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER File
            Filename string which needs to be downloaded from the repository.

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER OutFile
            A string representing the local file path to download the GitHub file to.

        .NOTES
            Name: Get-GitHubRepoFile
            Author: Jeff Bolduan
            LASTEDIT: 4/26/2017

        .EXAMPLE
            Get-GitHubRepoFile -Username "Test" -Password "pass" -File "psscript.ps1" -Repo "MyFakeReop" -Org "MyFakeOrg" -OutFile "C:\temp\psscript.ps1" -server "ServerFQDN"

    #>

    [CmdletBinding()]
    param(
        
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$File,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Repo,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Org,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$OutFile,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$org/$Repo/contents/$File"
    $RESTRequest = Invoke-RestMethod -Method Get -Uri $URI -Headers $Headers
    if($RESTRequest.download_url -eq $null) {
        throw [System.IO.IOException]
    } 
    else {
        $WebRequest = Invoke-WebRequest -Uri $RESTRequest.download_url -Headers $Headers -OutFile $OutFile
    }
}
#endregion

#region Get-GitHubRepoFileContent
function Get-GitHubRepoFileContent {
    <#
        .SYNOPSIS
            Gets and then returns the contents of a GitHub repo file.

        .DESCRIPTION
            Takes in a username, password, filename, repository, organization and then returns the contents
            of a file from the GitHub repository.

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER File
            Filename string which needs to be downloaded from the repository. This should be the path to the file if it's not
            in the root of the repository for example "fizz/buzz.txt" and keep in mind it should be the forward slashes.

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.
        
        .PARAMETER Server
            An optional parameter for the fully qualified domain name of a github server, defaults to github.com but can be an internal
            enterprise server.

        .NOTES
            Name: Get-GitHubRepoFile
            Author: Jeff Bolduan
            LASTEDIT: 10/26/2017

        .EXAMPLE
            $GitHubHeaders = New-GitHubHeader -psCreds (Get-Credential)
            
            Get-GitHubRepoFile -headers $GitHubHeaders -File "psscript.ps1" -Repo "MyFakeReop" -Org "MyFakeOrg" -server "github.foo.bar"

    #>

    [CmdletBinding()]
    [Alias("Get-GitHubRepoContent")]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.Collections.Hashtable]$headers,
        
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$File,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Repo,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Org,

        ## The Default is public github but you can set this if you are running your own Enterprise Github server\
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$server = 'github.com'
    )
    
    if ($server -eq 'github.com') { $Connection = "https://api.github.com" }
    else { $Connection = "https://$server/api/v3" }
    
    Write-Verbose -Message "[VariableValue:Connection] :: $Connection"
    
    $URI = "$Connection/repos/$org/$Repo/contents/$File"
    
    Write-Verbose -Message "[VariableValue:URI] :: $URI"
    
    $RESTRequest = Invoke-RestMethod -Method Get -Uri $URI -Headers $Headers
    
    Write-Verbose -Message "[VariableValue:RESTRequest] :: $RESTRequest"

    return([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($RESTRequest.content)))
}
#endregion

#region Get-GitHubTree
function Get-GitHubTree {
    <#
        .SYNOPSIS
            Get a specific reference or all references for a specific repo

        .DESCRIPTION
            Get a specific reference or all references for a specific repo, use -ref for a specific reference

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER sha
            Sha of tree, use (Get-GitHubCommit -authToken $ghAuthToken -Repo $Repo -Org $Org -server $server -sha $sha).tree.sha to get the sha you need

        .NOTES
            Name: Get-GitHubRepoRefs
            Author: Travis Sobeck
            LASTEDIT: 4/26/2017

        .EXAMPLE
            

        .EXAMPLE
            

    #>

    [CmdletBinding()]
    param(
        
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$sha,

        [switch]$recurse,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    $data = "trees/$sha"
    if ($recurse){$data += "?recursive=1"}
    Get-GitHubBase -headers $headers -Repo $Repo -Org $Org -server $server -data $data
}
#endregion

#region Get-GitHubRepoUnZipped
function Get-GitHubRepoUnZipped {
    <#
        .SYNOPSIS
            Get a GitHub Repo.

        .DESCRIPTION
            Takes in a username, password, repository, organization and a folder to output to then downloads the files
            from the repository.

        .PARAMETER headers
                Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER OutFolder
            A string representing the local file path to download the GitHub Reop file to.


        .EXAMPLE
            Get-GitHubRepoUnZipped -authToken $authToken -Repo $repo -Org $org -OutFolder $pathToFolder.
    #>


    [CmdletBinding()]
    param(
        
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Org,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$repo,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$outFolder,

        [Parameter(Mandatory=$true)]
        [string]$ref = "master",

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    # validate folder exits #
    if (-not(Test-Path $outFolder)){$null = New-Item $outFolder -ItemType Directory -Force}
    # get zip
    Get-GitHubRepoZip -Org $org -repo $repo -OutFile "$outFolder\$repo.zip" -ref $ref -server $server -headers $headers
    # unzip
    Expand-Archive -Path "$outFolder\$repo.zip" -DestinationPath $outFolder -Force
    # get the actual folder name, yeah this looks funky but OpenRead locks the file, this is need to get the folder name and still remove the zip file later
    $scriptblock = {Param( [string]$path)
        $null = [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
        $folder = [IO.Compression.ZipFile]::OpenRead((Get-Item -Path $path).FullName).Entries[0].FullName
        $folder = $folder.TrimEnd('/') # trip the stupid trailing slash
        $folder
    }
    $job = Start-Job -Name 'temp' -ArgumentList "$outFolder\$repo.zip" -ScriptBlock $scriptblock
    do{Start-Sleep -Seconds 1}until((Get-Job -Id $job.Id).State -eq 'Completed')
    $folder = Receive-Job -Job $job
    
    # rename the folder the the repo
    Rename-Item -Path "$outFolder\$folder" -NewName "$repo"-Force
    Remove-Item -Path "$outFolder\$repo.zip" -Force
}
#endregion

#region Get-GitHubRepoZip
function Get-GitHubRepoZip {
    <#
        .SYNOPSIS
            Get a GitHub Repo and download to zip file.

        .DESCRIPTION
            Takes in a PSCredention or Auth Key if needed, repository, organization and a file to output to then downloads the file
            from the repository.

        .PARAMETER headers
                Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER OutFile
            A string representing the local file path to download the GitHub Zip file to.


        .EXAMPLE
            Get-GitHubRepoZip -authToken $authToken -Repo $repo -Org $org -OutFile $outFile -server "ServerFQDN"

    #>

    [CmdletBinding()]
    param(

        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Org,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$repo,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$OutFile,

        [Parameter(Mandatory=$true)]
        [string]$ref = "master",

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$Org/$repo/zipball/$ref"

    Invoke-RestMethod -Method Get -Uri $URI -Headers $Headers -OutFile $OutFile
}
#endregion

#region New-GitHubBlob
function New-GitHubBlob {
    <#
        .SYNOPSIS
            Create a new Blob

        .DESCRIPTION
            Create a new Blob

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER filePath
            Path to file to be added/modified

        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE
           
    #>

    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory)]
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$filePath,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$org/$Repo/git/blobs"
    $content = $base64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((Get-Content -Path $filePath -Raw)))
    $json = @{"content" = $content;"encoding" = "base64"} | ConvertTo-Json -Depth 3
    Invoke-RestMethod -Method Post -Uri $URI -Headers $Headers -Body $json
}
#endregion

#region New-GitHubCommit
function New-GitHubCommit {
    <#
        .SYNOPSIS
            Create a new commit for a specific repo

        .DESCRIPTION
            Create a new commit for a specific repo

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER message
            The commit message
        
        .PARAMETER tree
            The SHA of the tree object this commit points to
            
        .PARAMETER parents
            The SHAs of the commits that were the parents of this commit. If omitted or empty, the commit will be written as a root commit. For a single parent, an array of one SHA should be provided; for a merge commit, an array of more than one should be provided.

        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE
            

    #>

    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory)]
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$message,

        [Parameter(Mandatory)]
        [string]$tree,

        [Parameter(Mandatory)]
        [array]$parents,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$org/$Repo/git/commits"
    $content = Get-Content $filePath
    $json = @{"message" = $message; "parents" = $parents; "tree" = $tree} | ConvertTo-Json -Depth 3
    Invoke-RestMethod -Method Post -Uri $URI -Headers $Headers -Body $json
}
#endregion

#region New-GitHubTree
function New-GitHubTree {
    <#
        .SYNOPSIS
            Get a specific commit for a specific repo

        .DESCRIPTION
            Get a specific commit for a specific repo,

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER path
            path to file in github
        
        .PARAMETER baseTree
            This is the SHA for the tree this is getting added onto, use Get-GitHubCommit and store ie $treeSha = $commit.tree.sha
            
        .PARAMETER mode
            The file mode; one of 100644 for file (blob), 100755 for executable (blob), 040000 for subdirectory (tree), 160000 for submodule (commit), or 120000 for a blob that specifies the path of a symlink

        .PARAMETER type
            Either blob, tree, or commit

        .PARAMETER blobSha
            Sha from the blob containing the content, use New-GitHubBlob and record the return sha

        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE

    #>

    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory)]
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$baseTree,

        [Parameter(Mandatory)]
        [string]$path,

        [Parameter(Mandatory)]
        [string]$mode,

        [Parameter(Mandatory)]
        [string]$type,

        [Parameter(Mandatory)]
        [string]$blobSha,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$org/$Repo/git/trees"
    $json = @{"base_tree" = $baseTree;"tree" = @(@{"path" = $path;"mode"=$mode;"type" = $type;"sha" = $blobSha})} | ConvertTo-Json -Depth 3
    Invoke-RestMethod -Method Post -Uri $URI -Headers $Headers -Body $json
}
#endregion

#region Set-GitHubCommit
function Set-GitHubCommit {
    <#
        .SYNOPSIS
            Update a reference to a new Commit

        .DESCRIPTION
            Update a reference to a new Commit

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER ref
            ref to be updated
        
        .PARAMETER sha
            SHA to update reference to, get this from New-GitHubCommit
            
        .PARAMETER parents
            The SHAs of the commits that were the parents of this commit. If omitted or empty, the commit will be written as a root commit. For a single parent, an array of one SHA should be provided; for a merge commit, an array of more than one should be provided.

        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 6/20/2017

        .EXAMPLE
            

    #>

    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory)]
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]
        [string]$ref,

        [Parameter(Mandatory)]
        [string]$sha,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    if ($server -eq 'github.com'){$conn = "https://api.github.com"}
    else{$conn = "https://$server/api/v3"}
    $URI = "$conn/repos/$org/$Repo/git/$ref"
    $json = @{"sha" = $sha;"force"=$true} | ConvertTo-Json -Depth 3
    Invoke-RestMethod -Method Patch -Uri $URI -Headers $Headers -Body $json
}
#endregion

#region Update-GitHubRepo
function Update-GitHubRepo {
    <#
        .SYNOPSIS
            Get a specific reference or all references for a specific repo

        .DESCRIPTION
            Get a specific reference or all references for a specific repo, use -ref for a specific reference

        .PARAMETER headers
            Get this from New-GitHubHeader

        .PARAMETER ref
            Specific ref, run the command without it to get a list example would be.

        .PARAMETER Repo
            Repository name string which is used to identify which repository under the organization to go into.

        .PARAMETER Org
            Organization name string which is used to identify which organization in the GitHub instance to go into.

        .PARAMETER message
            The commit message

        .PARAMETER path
            path to file in github

        .PARAMETER filePath
            Path to file to be added/modified

        .NOTES
            Author: Travis Sobeck
            LASTEDIT: 4/26/2017

        .EXAMPLE
            

    #>

    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory)]
        [System.Collections.Hashtable]$headers,

        [Parameter(Mandatory)]
        [string]$Repo,

        [Parameter(Mandatory)]
        [string]$Org,

        [Parameter(Mandatory)]        
        [string]$ref,

        [Parameter(Mandatory)]
        [string]$message,

        [Parameter(Mandatory)]
        [string]$path,

        [Parameter(Mandatory)]
        [string]$filePath,

        ## The Default is public github but you can se this if you are running your own Enterprise Github server
        [string]$server = 'github.com'
    )

    try{
        # Get reference to head of ref provided and record Sha
        $reference = Get-GitHubRepoRef -headers $headers -Repo $Repo -Org $Org -server $server -ref $ref
        $sha = $reference.object.sha
        # get commit for that ref and store Sha
        $commit = Get-GitHubCommit -headers $headers -Repo $Repo -Org $Org -server $server -sha $sha
        $treeSha = $commit.tree.sha
        # Creat Blob
        $blob = New-GitHubBlob -headers $headers -Repo $Repo -Org $Org -server $server -filePath $filePath
        # create new Tree
        $tree = New-GitHubTree -headers $headers -Repo $Repo -Org $Org -server $server -path $path -blobSha $blob.sha -baseTree $treeSha -mode 100644 -type 'blob'
        # create new commit
        $newCommit = New-GitHubCommit -headers $headers -Repo $Repo -Org $Org -server $server -message $message -tree $tree.sha -parents @($sha)
        # update head to point at new commint
        Set-GitHubCommit -headers $headers -Repo $Repo -Org $Org -server $server -ref $ref -sha $newCommit.sha
    }
    catch{$Error[0]}
}
#endregion

##########################################################################################################################
Export-ModuleMember -Function *
# SIG # Begin signature block
# MIIaxgYJKoZIhvcNAQcCoIIatzCCGrMCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUC7moU9utR2SWqBzhVQ5xi4nW
# TLGgghW3MIIEmTCCA4GgAwIBAgIPFojwOSVeY45pFDkH5jMLMA0GCSqGSIb3DQEB
# BQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQg
# TGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNV
# BAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJG
# aXJzdC1PYmplY3QwHhcNMTUxMjMxMDAwMDAwWhcNMTkwNzA5MTg0MDM2WjCBhDEL
# MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
# BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKjAoBgNVBAMT
# IUNPTU9ETyBTSEEtMSBUaW1lIFN0YW1waW5nIFNpZ25lcjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAOnpPd/XNwjJHjiyUlNCbSLxscQGBGue/YJ0UEN9
# xqC7H075AnEmse9D2IOMSPznD5d6muuc3qajDjscRBh1jnilF2n+SRik4rtcTv6O
# KlR6UPDV9syR55l51955lNeWM/4Og74iv2MWLKPdKBuvPavql9LxvwQQ5z1IRf0f
# aGXBf1mZacAiMQxibqdcZQEhsGPEIhgn7ub80gA9Ry6ouIZWXQTcExclbhzfRA8V
# zbfbpVd2Qm8AaIKZ0uPB3vCLlFdM7AiQIiHOIiuYDELmQpOUmJPv/QbZP7xbm1Q8
# ILHuatZHesWrgOkwmt7xpD9VTQoJNIp1KdJprZcPUL/4ygkCAwEAAaOB9DCB8TAf
# BgNVHSMEGDAWgBTa7WR0FJwUPKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQUjmstM2v0
# M6eTsxOapeAK9xI1aogwDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny
# bC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDA1BggrBgEF
# BQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w
# DQYJKoZIhvcNAQEFBQADggEBALozJEBAjHzbWJ+zYJiy9cAx/usfblD2CuDk5oGt
# Joei3/2z2vRz8wD7KRuJGxU+22tSkyvErDmB1zxnV5o5NuAoCJrjOU+biQl/e8Vh
# f1mJMiUKaq4aPvCiJ6i2w7iH9xYESEE9XNjsn00gMQTZZaHtzWkHUxY93TYCCojr
# QOUGMAu4Fkvc77xVCf/GPhIudrPczkLv+XZX4bcKBUCYWJpdcRaTcYxlgepv84n3
# +3OttOe/2Y5vqgtPJfO44dXddZhogfiqwNGAwsTEOYnB9smebNd0+dmX+E/CmgrN
# Xo/4GengpZ/E8JIh5i15Jcki+cPwOoRXrToW9GOUEB1d0MYwggV3MIIEX6ADAgEC
# AhAT6ihwW/Ts7Qw2YwmAYUM2MA0GCSqGSIb3DQEBDAUAMG8xCzAJBgNVBAYTAlNF
# MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJu
# YWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJv
# b3QwHhcNMDAwNTMwMTA0ODM4WhcNMjAwNTMwMTA0ODM4WjCBiDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4w
# HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVz
# dCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzO
# iZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwW
# IJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YU
# VD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1da
# t//O+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+
# UzeQc0PzMsNT79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/z
# JSZrM233bkf6c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLa
# qUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxb
# gtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9A
# qURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
# eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwID
# AQABo4H0MIHxMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1QaMB0GA1Ud
# DgQWBBRTeb9aqitKz1SA4dibwJ3ysgNmyzAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T
# AQH/BAUwAwEB/zARBgNVHSAECjAIMAYGBFUdIAAwRAYDVR0fBD0wOzA5oDegNYYz
# aHR0cDovL2NybC51c2VydHJ1c3QuY29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3Qu
# Y3JsMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNl
# cnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAQEAk2X2N4OVD17Dghwf1nfnPIrA
# qgnw6Qsm8eDCanWhx3nJuVJgyCkSDvCtA9YJxHbf5aaBladG2oJXqZWSxbaPAyJs
# M3fBezIXbgfOWhRBOgUkG/YUBjuoJSQOu8wqdd25cEE/fNBjNiEHH0b/YKSR4We8
# 3h9+GRTJY2eR6mcHa7SPi8BuQ33DoYBssh68U4V93JChpLwt70ZyVzUFv7tGu25t
# N5m2/yOSkcZuQPiPKVbqX9VfFFOs8E9h6vcizKdWC+K4NB8m2XsZBWg/ujzUOAai
# 0+aPDuO0cW1AQsWEtECVK/RloEh59h2BY5adT3Xg+HzkjqnR8q2Ks4zHIc3C7zCC
# BawwggSUoAMCAQICEHJNXiAT1cKRQFXzfFSJVHEwDQYJKoZIhvcNAQELBQAwfDEL
# MAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1JMRIwEAYDVQQHEwlBbm4gQXJib3IxEjAQ
# BgNVBAoTCUludGVybmV0MjERMA8GA1UECxMISW5Db21tb24xJTAjBgNVBAMTHElu
# Q29tbW9uIFJTQSBDb2RlIFNpZ25pbmcgQ0EwHhcNMTcxMjE0MDAwMDAwWhcNMjAx
# MjEzMjM1OTU5WjCByzELMAkGA1UEBhMCVVMxDjAMBgNVBBEMBTU1NDU1MRIwEAYD
# VQQIDAlNaW5uZXNvdGExFDASBgNVBAcMC01pbm5lYXBvbGlzMRgwFgYDVQQJDA8x
# MDAgVW5pb24gU3QgU0UxIDAeBgNVBAoMF1VuaXZlcnNpdHkgb2YgTWlubmVzb3Rh
# MSQwIgYDVQQLDBtDb21wdXRlciBhbmQgRGV2aWNlIFN1cHBvcnQxIDAeBgNVBAMM
# F1VuaXZlcnNpdHkgb2YgTWlubmVzb3RhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
# MIIBCgKCAQEAwk6kLE9u+tWv0JUkIJSn5pWfa09g6cqFLucCXomNj9NYj8t+JfPn
# a3gC6LHv3OQAUDHOoC5H+8N3ea7qVGYIiwPRHzXOGqG/tVaiU5s5hG3vBhfRX8W1
# /2g4/hpgeXUzrxYn/2c5SOGGy0MU1ZJyUSFEdsjXHEV7HXK4qmFGV9RJxtiLZH1q
# UldCglxcj7zw0QnUdG6oAxpwTCeVp057/WXbnIR8a0gPse+y/new5+CBUGTAvrw6
# K2BrJQVsdIIVn/q+BbcZxh9PpeZfTtsi6lgkvy0bUWtl5sSpd75+hvw4Sl3HAaWZ
# toWN7LPmbDbbVRO2Arv4doh4Chod4wJ5xQIDAQABo4IB2DCCAdQwHwYDVR0jBBgw
# FoAUrjUjF///Bj2cUOCMJGUzHnAQiKIwHQYDVR0OBBYEFF4LEhElVUvT8n5txOJS
# NAczooSAMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
# CCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBmBgNVHSAEXzBdMFsGDCsGAQQB
# riMBBAMCATBLMEkGCCsGAQUFBwIBFj1odHRwczovL3d3dy5pbmNvbW1vbi5vcmcv
# Y2VydC9yZXBvc2l0b3J5L2Nwc19jb2RlX3NpZ25pbmcucGRmMEkGA1UdHwRCMEAw
# PqA8oDqGOGh0dHA6Ly9jcmwuaW5jb21tb24tcnNhLm9yZy9JbkNvbW1vblJTQUNv
# ZGVTaWduaW5nQ0EuY3JsMH4GCCsGAQUFBwEBBHIwcDBEBggrBgEFBQcwAoY4aHR0
# cDovL2NydC5pbmNvbW1vbi1yc2Eub3JnL0luQ29tbW9uUlNBQ29kZVNpZ25pbmdD
# QS5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmluY29tbW9uLXJzYS5vcmcw
# GQYDVR0RBBIwEIEOb2l0bXB0QHVtbi5lZHUwDQYJKoZIhvcNAQELBQADggEBAENR
# lesMKmBaZ0g68lttYEMtaPiz+DaNpOlXBs1gH66aghB1aP6iiRJcFVasGLUVFncd
# G1xbw503LTrBUc5PECMVDVF7KKCfHA1OeFV9vOWyvdVgbe3paDy1sj4CADO2D0gn
# xcGiZoFhEZiBkTvSsj4S3GXZEvoFHJxJLw2kvdLnzy0gH/b/b/yblwA1fKXw4loc
# UpDM6qTwM7SiKgkQ5W7/280EYu8BI6c8rpiJmqM1tZLcpswuavB00T52Y+ZZmz3t
# MMVgFHn9pFFltYr3s3bEek7I6pU8unISbiyQzxqhIUKaBi8hy8LgoY5UnGjX5jHs
# IvINzms+JX5Ity02sL0wggXrMIID06ADAgECAhBl4eLj1d5QRYXzJiSABeLUMA0G
# CSqGSIb3DQEBDQUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNl
# eTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1Qg
# TmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1
# dGhvcml0eTAeFw0xNDA5MTkwMDAwMDBaFw0yNDA5MTgyMzU5NTlaMHwxCzAJBgNV
# BAYTAlVTMQswCQYDVQQIEwJNSTESMBAGA1UEBxMJQW5uIEFyYm9yMRIwEAYDVQQK
# EwlJbnRlcm5ldDIxETAPBgNVBAsTCEluQ29tbW9uMSUwIwYDVQQDExxJbkNvbW1v
# biBSU0EgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEAwKAvix56u2p1rPg+3KO6OSLK86N25L99MCfmutOYMlYjXAaGlw2A6O2i
# gTXrC/Zefqk+aHP9ndRnec6q6mi3GdscdjpZh11emcehsriphHMMzKuHRhxqx+85
# Jb6n3dosNXA2HSIuIDvd4xwOPzSf5X3+VYBbBnyCV4RV8zj78gw2qblessWBRyN9
# EoGgwAEoPgP5OJejrQLyAmj91QGr9dVRTVDTFyJG5XMY4DrkN3dRyJ59UopPgNwm
# ucBMyvxR+hAJEXpXKnPE4CEqbMJUvRw+g/hbqSzx+tt4z9mJmm2j/w2nP35MViPW
# Cb7hpR2LB8W/499Yqu+kr4LLBfgKCQIDAQABo4IBWjCCAVYwHwYDVR0jBBgwFoAU
# U3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFK41Ixf//wY9nFDgjCRlMx5w
# EIiiMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQM
# MAoGCCsGAQUFBwMDMBEGA1UdIAQKMAgwBgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BB
# hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh
# dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo
# dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j
# cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI
# hvcNAQENBQADggIBAEYstn9qTiVmvZxqpqrQnr0Prk41/PA4J8HHnQTJgjTbhuET
# 98GWjTBEE9I17Xn3V1yTphJXbat5l8EmZN/JXMvDNqJtkyOh26owAmvquMCF1pKi
# QWyuDDllxR9MECp6xF4wnH1Mcs4WeLOrQPy+C5kWE5gg/7K6c9G1VNwLkl/po9OR
# PljxKKeFhPg9+Ti3JzHIxW7LdyljffccWiuNFR51/BJHAZIqUDw3LsrdYWzgg4x0
# 6tgMvOEf0nITelpFTxqVvMtJhnOfZbpdXZQ5o1TspxfTEVOQAsp05HUNCXyhznlV
# Lr0JaNkM7edgk59zmdTbSGdMq8Ztuu6VyrivOlMSPWmay5MjvwTzuNorbwBv0DL+
# 7cyZBp7NYZou+DoGd1lFZN0jU5IsQKgm3+00pnnJ67crdFwfz/8bq3MhTiKOWEb0
# 4FT3OZVp+jzvaChHWLQ8gbCORgClaZq1H3aqI7JeRkWEEEp6Tv4WAVsr/i7LoXU7
# 2gOb8CAzPFqwI4Excdrxp0I4OXbECHlDqU4sTInqwlMwofmxeO4u94196qIqJQl+
# 8Sykl06VktqMux84Iw3ZQLH08J8LaJ+WDUycc4OjY61I7FGxCDkbSQf3npXeRFm0
# IBn8GiW+TRDk6J2XJFLWEtVZmhboFlBLoUlqHUCKu0QOhU/+AEOqnY98j2zRMYIE
# eTCCBHUCAQEwgZAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1JMRIwEAYDVQQH
# EwlBbm4gQXJib3IxEjAQBgNVBAoTCUludGVybmV0MjERMA8GA1UECxMISW5Db21t
# b24xJTAjBgNVBAMTHEluQ29tbW9uIFJTQSBDb2RlIFNpZ25pbmcgQ0ECEHJNXiAT
# 1cKRQFXzfFSJVHEwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKEC
# gAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG
# CisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFK4ITJZDJCgj49OPY3bSQ1i1ojlD
# MA0GCSqGSIb3DQEBAQUABIIBADmNvYG7vLPuQzZV1IwVc6kSL+34chm3r0MuRIie
# u1IaQuufCEw6CFchf48z+Pj7LswFu3/Kaoi2PkbGl5R54fZu0434CtFuADwpJP2m
# 1aDVU1Q07LZ+1P5Hf8Wws7KliZdG2KJt+3oLrul7a54o61pFMQqVcJFvmmUr5nN5
# 2RFrVMjWmaw44+LIDeYD4hh34N90TxNsO6VOdLfkMZigLlOrmnk7gO69bnRc7H3a
# YNPV4dh0Kp4LYROq8+Z/LqAj8Ep5U/JB3sVncFLS0ImiLDzLGZ/t+Y+BJf4bxdJt
# sSjVxOVJdiwM8XUl3yFtkVd0Fz7kBBKaUaeb6+/Q96JcJaShggJDMIICPwYJKoZI
# hvcNAQkGMYICMDCCAiwCAQEwgakwgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJV
# VDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJV
# U1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0w
# GwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdAIPFojwOSVeY45pFDkH5jMLMAkG
# BSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ
# BTEPFw0xODAyMTYxOTIwMzZaMCMGCSqGSIb3DQEJBDEWBBSzEiVBR1sIMTO9pJJt
# 8mBjCpG18DANBgkqhkiG9w0BAQEFAASCAQA6zFNHdK+yxtYBpYacb5txvtXu/043
# s07+UX1xxw8YYz/obpnsaTPEmb7h8YMD2e0kLOx39XLkE8IPpfk/n9hIPFXhjJhm
# dqK3NDiAZ5ciMp9zXePwqhJ4nGHnmIOTOBJO62Nsfe1fXRi7jBZ9lPolKKcBh0cv
# Vw+T5+EXnoZxpT8BdQNcToOJBuFJsO6fEEHT/XPQZwwx0hh4s55ENr4sXc6UYubt
# Y/K8hjV/8r+C/6BeupLJi2Bw9Jd2gPUHvCvz67kSuoeRhDSSQyc9a70wXmugUFw7
# 5oNQ5FLpUzj+Y2pbvWBGdpTOZohn6MaXXDzqrTMzT+NANxhgipv8zv78
# SIG # End signature block