PowerShellForGitHub.Content.psm1

function Test-Overlap {
    <#
    .SYNOPSIS
        Tests a value against muiltiple filter conditions, accepting any single fit.
     
    .DESCRIPTION
        Tests a value against muiltiple filter conditions, accepting any single fit.
        The comparison operator used is the "-like"
 
        This command will return $true if at least a single filter condition applies to the tested value.
        Is not case sensitive.
     
    .PARAMETER Value
        The value to test against the conditions.
     
    .PARAMETER Filter
        One or multiple filter conditions using wildcard comparison.
        E.g.: A*,B*,*Z would accept any input that starts with A or B or - irrespective of th starting letter - ends with z
     
    .PARAMETER Not
        Reverses the output - a $true result becomes $false and vice versa.
     
    .EXAMPLE
        PC C:\> Test-Overlap -Value Fred -Filter A*,B*,*D
 
        Tests whether "Fred" starts with "A" or "B" or ands with "D" (which it does)
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Value,

        [Parameter(Mandatory = $true)]
        [string[]]
        $Filter,

        [switch]
        $Not
    )

    foreach ($filterString in $Filter) {
        if ($Value -like $filterString) { return $Not -eq $false }
    }
    $Not -eq $true
}

function Get-GithubFileData {
    <#
    .SYNOPSIS
        Retrieves the data of a textfile from github.
     
    .DESCRIPTION
        Retrieves the data of a textfile from github.
     
    .PARAMETER Owner
        Owner of the Repository the file is from.
        Optional, decorative parameter used to enrich the output object.
     
    .PARAMETER Repository
        The name of the Repository the file is from.
        Optional, decorative parameter used to enrich the output object.
     
    .PARAMETER BranchName
        The Branch the file is a paart of.
        Optional, decorative parameter used to enrich the output object.
     
    .PARAMETER Path
        The relative Path of the file within its branch.
        Optional, decorative parameter used to enrich the output object.
     
    .PARAMETER Name
        The name of the file.
        Optional, decorative parameter used to enrich the output object.
     
    .PARAMETER Url
        Url to the file toretrieve
     
    .EXAMPLE
        PS C:\> Get-GithubTree -Owner FriedrichWeinmann -Repository PowerShellForGithub.Content -BranchName master | Get-GithubFileData
     
        Download all files from the master branch of the repository PowerShellForGithub.Content
    #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]
        $Owner,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]
        $Repository,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]
        $BranchName,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]
        $Path,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]
        $Name,

        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string]
        $Url
    )

    process {
        if ($Url -notlike '*/blobs/*') { return }

        $fileData = Invoke-GHRestMethod -Method Get -UriFragment ($Url -replace '^https://api.github.com')
        $contentB64 = $fileData.content -replace "\n"
        $contentBytes = [convert]::FromBase64String($contentB64)
        $contentText = [System.Text.Encoding]::UTF8.GetString($contentBytes)
        
        [PSCustomObject]@{
            Name       = "$Owner/$Repository/$Path [$BranchName]"
            Content    = $contentText

            Owner      = $Owner
            Repository = $Repository
            Branch     = $BranchName
            FileName   = $Name
        }
    }
}

function Get-GithubRepositoryFile {
    <#
    .SYNOPSIS
        Search an organization's repositories for files.
     
    .DESCRIPTION
        Search an organization's repositories for files.
        Includes file-content.
     
    .PARAMETER Organization
        The Organization or private account to search.
     
    .PARAMETER Repository
        Filter by repository name.
        Defaults to '*'
     
    .PARAMETER Branch
        Filter by branch name.
        Defaults to '*'
     
    .PARAMETER Name
        Filter by filename.
        Defaults to '*'
     
    .EXAMPLE
        PS C:\> Get-GithubRepositoryFile -Organization FriedrichWeinmann -Name *.ps1,*psm1
 
        Search all github projects maintained directly by Friedrich Weinmann and download all ps1 and psm1 files from all branches of them all.
        Hint: This may take a while and will return loooots of data ;)
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Organization,

        [string[]]
        $Repository = '*',

        [string[]]
        $Branch = '*',

        [string[]]
        $Name = '*'
    )

    process {
        Get-GitHubRepository -OwnerName $Organization | Where-Object {
            Test-Overlap -Value $_.Name -Filter $Repository
        } | Get-GitHubRepositoryBranch | Where-Object {
            Test-Overlap -Value $_.Name -Filter $Branch
        } | Get-GithubTree | Where-Object {
            Test-Overlap -Value $_.Name -Filter $Name
        } | Get-GithubFileData
    }
}

function Get-GithubTree {
    <#
    .SYNOPSIS
        Returns a list of all files and folders in the selected branch.
     
    .DESCRIPTION
        Returns a list of all files and folders in the selected branch.
     
    .PARAMETER Owner
        The owner of the repository.
        Can be an organization or a personal account name.
     
    .PARAMETER Repository
        The name of the repository to scan.
     
    .PARAMETER RepositoryUrl
        The full link to the repository to scan
     
    .PARAMETER BranchName
        The name of the branch to scan.
     
    .EXAMPLE
        PS C:\> Get-GithubTree -Owner FriedrichWeinmann -Repository PowerShellForGithub.Content -BranchName master
 
        Returns all files and folders in the master branch of the PowerShellForGithub.Content repository of FriedrichWeinmann
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'property')]
        [string]
        $Owner,

        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'property')]
        [string]
        $Repository,

        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'url')]
        [string]
        $RepositoryUrl,

        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string]
        $BranchName
    )

    process {
        if ($RepositoryUrl) {
            $parts = $RepositoryUrl -split "/"
            $Owner = $parts[-2]
            $Repository = $parts[-1]
        }
        $result = Invoke-GHRestMethod -Method Get -UriFragment "/repos/$Owner/$Repository/git/trees/$($BranchName)?recursive=1"
        foreach ($item in $result.tree) {
            [PSCustomObject]@{
                Name       = ($item.Path -split "/")[-1]
                Path       = $item.Path
                Mode       = $item.mode
                Type       = $item.type
                Hash       = $item.sha
                Size       = $item.size
                Url        = $item.url
                Owner      = $Owner
                Repository = $Repository
                BranchName = $BranchName
            }
        }
    }
}