GitBones.psm1



class GitBonesTemplate {
   
    [string] 
    hidden $BonesURL = 'https://gitlab.com/GitBones/gitbones/raw/master/templates/templates.json'
    ## Name of the GitBones Template
    [string]
    $Name
    ## The HTTPS URL of the GitBones Template
    [string]
    $URL
    ## Short description of the project
    [string]
    $Description
    ## The group that is managing the repository of the URL
    [string]
    $Maintainer
    ## The original Author of the project
    [string]
    $Author
    ## The identified Git Host Server (e.g. GitLab, GitHub, Bitbucket)
    ## if project is built off of specific Git Host service
    [string]
    $GitHost
    ## The specific CI tool being used for the project
    [string]
    $CI
    ## The general topic of the template
    [string]
    $Topic
    ## The specific programming language or code-base of the project
    [string]
    $Language
    ## Informs if the project has submodules in it
    [bool]
    $Submodules

    GitBonesTemplate (
        [string]$Name,
        [string]$URL,
        [string]$Description,
        [string]$Maintainer,
        [string]$Author,
        [string]$GitHost,
        [string]$CI,
        [string]$Topic,
        [string]$Language,
        [bool]$Submodules
    )
    {
        $this.Name =$Name
        $this.URL = $URL
        $this.Description = $Description
        $this.Maintainer = $Maintainer
        $this.Author = $Author
        $this.GitHost = $GitHost
        $this.CI = $CI
        $this.Topic = $Topic
        $this.Language = $Language
        $this.Submodules = $Submodules
    }

    GitBonesTemplate([string]$Name) {
        $Response = invoke-restmethod -uri $this.BonesURL -Method Get
        $Result = $Response.Projects | Where-Object -Property Name -LIKE $Name
        $this.Name = $Result[0].Name
        $this.URL = $Result[0].URL
        $this.Description = $Result[0].Description
        $this.Maintainer = $Result[0].Maintainer
        $this.Author = $Result[0].Author
        $this.GitHost = $Result[0].GitHost
        $this.CI = $Result[0].CI
        $this.Topic = $Result[0].Topic
        $this.Language = $Result[0].Language
        $this.Submodules = $Result[0].Submodules
    }

    [void]CreateProject([string]$NewGitProjectUri) {
        [string]$TemplateToClone = $this.URL
        $project = $($NewGitProjectUri.Split('/')[-1]) -replace ".git", ""
        New-Item -ItemType Directory -Name $project
        Set-Location $project
        git clone $TemplateToClone ./ --quiet 
        if(test-path ./.git -ErrorAction SilentlyContinue){
            remove-item -Path ./.git -Force -Recurse
        }
        git init
        git remote add origin $NewGitProjectUri
    }

}# end GitBonesTemplate

function Invoke-GitInstall {
    PARAM()
    BEGIN {
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
    }# end BEGIN
    PROCESS {
        if(-NOT(Test-GitApp)){
            ## heavily pulled from https://github.com/tomlarse/Install-Git/blob/master/Install-Git/Install-Git.ps1
            ## only run if on a Windows OS
            if (Test-WindowsOS){
                $gitExePath = "$env:ProgramFiles\Git\bin\git.exe"
                foreach ($asset in (Invoke-RestMethod https://api.github.com/repos/git-for-windows/git/releases/latest).assets) {
                    if ($asset.name -match 'Git-\d*\.\d*\.\d*.\d*-64-bit\.exe') {
                        $dlurl = $asset.browser_download_url
                    }
                }# end foreach
                
                if (!(Test-Path $gitExePath -ErrorAction SilentlyContinue)) {
                    Remove-Item -Force $env:TEMP\git-stable.exe -ErrorAction SilentlyContinue
                }# end if
                try{
                    Invoke-WebRequest -Uri $dlurl -OutFile $env:TEMP\git-stable.exe -ErrorAction Stop
                }
                catch{
                    Write-Error "Failed to download git.exe" -ErrorAction Stop
                }# end try-catch
                try {
                    Start-Process -Wait $env:TEMP\git-stable.exe -ArgumentList /silent -ErrorAction Stop
                    Write-Host "Installation complete!" -ForegroundColor Green
                }
                catch{
                    Write-Error "Failed to install git.exe" -ErrorAction Stop
                }# end try-catch
            }
            else{
                Write-Host "This script is currently only supported on the Windows operating system." 
                Write-Host "If running Linux, use packagement solution to install."
                Write-Host "If running MacOS, use brew and using Xcode command line tools run 'git --version' and you should be prompted to install."
            }
        }
        else {
            Write-Host "Git correctly installed"
        }
    }# end PROCESS
    END {}# end END
}# end Invoke-GitInstall
Export-ModuleMember -Function Invoke-GitInstall

function Get-GitBonesTemplate {
<#
.Synopsis
   Retrieves all supported GitBones Templates
.DESCRIPTION
   Long description
.EXAMPLE
   Get-GitBonesTemplate -GitBonesUri 'https://gitlab.com/git-templates/default.git'
.EXAMPLE
   BonesList -Bones 'https://gitlab.com/git-templates/default.git'
.EXAMPLE
   Get-GitBonesTemplate -Topic 'CloudFormation'
.EXAMPLE
   BonesList -Topic 'CloudFormation'
.EXAMPLE
   Get-GitBonesTemplate -Author 'AWS'
.EXAMPLE
   BonesList -Author 'AWS'
.EXAMPLE
   Get-GitBonesTemplate -Language 'PowerShell'
.EXAMPLE
   BonesList -Application 'PowerShell'
#>

    [CmdletBinding(SupportsShouldProcess=$true, 
        ConfirmImpact='Medium')]
    [Alias('BonesList')]
    Param(
        # The GitBones Template HTTPS URL hosted on GitBones
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [Alias("Bones")]
        [string]$GitBonesUri,
        # Filter results based on GitBones Name keyword or phrase
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
        [string]$Name,
        # Filter results based on GitBones Topic keyword or phrase
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=2)]
        [string]$Topic,
        # # Filter results based on GitBones Author keyword or phrase
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=3)]
        [string]$Author,
        # # Filter results based on GitBones programming Language keyword or phrase
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=4)]
        [string]$Language
    )# end params

    BEGIN {
        Test-GitBonesConnection
        ## current location for the template master catalog
        $BonesURL = 'https://gitlab.com/GitBones/gitbones/raw/master/templates/templates.json'
        $Response = invoke-restmethod -uri $BonesURL -Method Get
    }# end BEGIN
    PROCESS{
        if($Response.Projects.Count -GE 1){
            $Result = $Response.Projects
            ## filter based on supplied URL
            if($GitBonesUri){
                $Result =  $Result | Where-Object -Property URL -LIKE $GitBonesUri
            }# end if GitBonesUri

            if($Name){
                $Result =  $Result | Where-Object -Property Name -LIKE "*$Name*"
            }# end if GitBonesUri

            ## filter based on supplied topic
            if($Topic){
                $Result =  $Result | Where-Object -Property Topic -LIKE "*$Topic*"
            }#enf if Topic

            ## filter based on supplied Author
            if($Author){
                $Result =  $Result | Where-Object -Property Author -LIKE "*$Author*"
            }# end if Author

            ## filter based on supplied programming language
            if($Language){
                $Result =  $Result | Where-Object -Property Language -LIKE "*$Language*"
            }#enf if application
        }
        else {
            Write-Error "GitBones connection is not returning queries at this time." -ErrorAction Stop 
        }# end else-if
    }# end PROCESS
    END{
        return $Result
    }# end END
}# end Get-GitBonesTemplate
Export-ModuleMember -Function Get-GitBonesTemplate -Alias BonesList

function New-GitBonesProject {
<#
.Synopsis
   Creates a git project skeleton directory based on GitBones user templates
.DESCRIPTION
   Long description
.EXAMPLE
   New-GitBonesProject -GitProjectUri 'git@gitlab.com:rolston/test.git' `
    -GitBonesName 'Gitlab-CloudFormation'
.EXAMPLE
   BonesInit -GitProjectUri 'git@gitlab.com:rolston/test.git' `
    -GitBonesName 'Gitlab-CloudFormation'
#>

    [CmdletBinding(SupportsShouldProcess=$true, 
                  ConfirmImpact='Medium')]
    [Alias('BonesInit')]
    Param(
        # Git Project SSH or HTTPS URL for new project
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$GitProjectUri,

        # The GitBones Project Name
        [Parameter(Mandatory=$false,
                   ValueFromPipeline=$false,
                   Position=1)]
        [ValidateNotNullOrEmpty()]
        [Alias("Bones")]
        [string]
        $GitBonesName
    )

    BEGIN {
        $GitBonesUri = 'https://gitlab.com/GitBones/gitbones/raw/master/templates/templates.json'
        if(!(Test-GitInstallation)){
            Write-Error "Missing git installation requirements" -ErrorAction Stop
        }
        if ((Invoke-WebRequest -Uri $GitBonesUri -ErrorAction SilentlyContinue -UseBasicParsing).StatusCode -EQ 200) {
            write-verbose "connection succeeded to bones template $GitBonesUri"
        }
        else {
            write-verbose "connection failed to bones template $GitBonesUri"
            Write-Error "Bones Template network connection fail: $GitBonesUri" -ErrorAction Stop
        }

    }# end BEGIN
    PROCESS{
        [GitBonesTemplate]$GitBonesResult = [GitBonesTemplate]::new($GitBonesName)
        if($GitBonesResult.URL){
            $GitBonesResult.CreateProject($GitProjectUri)
        }
        else {
            Write-Error "No Bones Project Template found. Check the name of the Bone Project Template" -ErrorAction Stop
        }
    }# end PROCESS
    END{

    }# end END
}# end New-GitBonesProject
Export-ModuleMember -Function New-GitBonesProject -Alias BonesInit


function Set-GitPath {
<#
.Synopsis
   Sets the path for Windows OS Git.exe installations
.DESCRIPTION
   Sets the path for Windows OS Git.exe installations
   looking at $env:PATH checking for "$env:ProgramFiles\Git\cmd"
   to be in the path. This functions requires the session to be
   running under elevated privileges.
.EXAMPLE
   Set-Path
#>

    [CmdletBinding(SupportsShouldProcess=$true, 
                  ConfirmImpact='Medium')]
    PARAM()
    if (Test-WindowsOS){
        ## verify git is installed prior to setting path
        if(Test-GitApp){
            ## git is installed, test if path is set in system path
            if(!(Test-GitPath)){
                if(Test-IsAdmin){
                $GitPath = "$env:ProgramFiles\Git\cmd"
                [Environment]::SetEnvironmentVariable("Path", $env:Path + ";$GitPath", [EnvironmentVariableTarget]::Machine)
                }
                else {
                    Write-Warning "To set path you will need to run session as admin"
                    Write-Warning "Path not set for Git installation"
                }
            }
            else {
                Write-Host "Git Path already set"
            }
        }
        else
        {
            Write-Warning "Cannot set path until Git is installed. Please run Invoke-GitInstall"
        }
    }# end if Windows OS
    else {
        Write-Host "Set-GitPath is only applicable to Windows OS."
    }
}# end Set-GitPath
Export-ModuleMember -Function Set-GitPath

function Test-GitApp {
    [CmdletBinding(SupportsShouldProcess=$true, 
                  ConfirmImpact='Medium')]
    PARAM()
    # Tests the Installation of Git
    if (Test-WindowsOS){
        Write-Verbose "System identified as Windows OS."
        $GitPath = "$env:ProgramFiles\Git\cmd"
        if(!(Test-Path -Path "$GitPath\git.exe" -ErrorAction SilentlyContinue)){
            return $false
        }
        else {
            return $true
        }# end if
    }# end if IsWindows
    else {
        ## leverage command -v to see if git is installed on Linux or Mac
        if(!(Invoke-Command -scriptblock {command -v git} -ErrorAction SilentlyContinue)){
            return $false
        }
        else {
            return $true
        }
    }# end elseif Linux or Mac OS
}# end Test-GitApp

function Test-GitBonesConnection {
    [CmdletBinding(SupportsShouldProcess=$true, 
                  ConfirmImpact='Medium')]
    PARAM()
    $GitBonesUri = 'https://gitlab.com/GitBones/gitbones/raw/master/templates/templates.json'
    if ((Invoke-WebRequest -Uri $GitBonesUri -ErrorAction SilentlyContinue -UseBasicParsing).StatusCode -EQ 200) {
        write-verbose "connection succeeded to bones template $GitBonesUri"
    }
    else {
        write-verbose "connection failed to bones template $GitBonesUri"
        Write-Error "Bones Template network connection fail: $GitBonesUri" -ErrorAction Stop
    }
    
}# end Test-GitBonesConnection

function Test-GitPath {
    ## Only for Windows do we need to check
    [CmdletBinding(SupportsShouldProcess=$true, 
                  ConfirmImpact='Medium')]
    PARAM()

    ## run only on Windows OS
    if (Test-WindowsOS){
        $GitPath = "$env:ProgramFiles\Git\cmd"
        if(($env:Path).Contains($GitPath)){
            return $true
        }
        else {
            return $false
        }# end if env:Path
    }
    else {
        ## system in either Linux or Mac
        ## and path is not an issue
        return $true
    }# end if-else
}# end Test-GitPath

function Test-GitInstallation {
    BEGIN {}# end BEGIN
    PROCESS {
        if(!(Test-GitApp)) {
                Write-Warning "Git application not installed, please run Invoke-GitInstall to setup Git.exe"
                return $false  
        }# end if
           
        if(!(Test-GitPath)){
            if(Test-WindowOS){ 
                Write-Warning "Git application not found under env:PATH, please run Set-GitPath to complete Git configuration"
                return $false
            }
        }
        return $true
    }# end PROCESS
    END {}# end END
}# end Test-GitInstallation

function Test-IsAdmin {
    ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
}# end Test-IsAdmin

function Test-WindowsOS {
    if ((!($IsLinux) -AND (!($IsMacOS)))){
        return $true
    }
    else {
        return $false
    }# end if-else
}# end Test-WindowsOS