tasks/New-Release.GitHub.build.ps1

param(
    # Base directory of all output (default to 'output')
    [string]$OutputDirectory = (property OutputDirectory (Join-Path $BuildRoot 'output')),

    $ChangelogPath = (property ChangelogPath 'CHANGELOG.md'),

    [string]
    $ProjectName = (property ProjectName $(
            #Find the module manifest to deduce the Project Name
            (Get-ChildItem $BuildRoot\*\*.psd1 | Where-Object {
                    ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
                    $(try {
                            Test-ModuleManifest $_.FullName -ErrorAction Stop
                        }
                        catch {
                            $false
                        }) }
            ).BaseName
        )
    ),

    [string]
    $ModuleVersion = (property ModuleVersion $(
            try {
                (gitversion | ConvertFrom-Json -ErrorAction Stop).InformationalVersion
            }
            catch {
                Write-Verbose "Error attempting to use GitVersion $($_)"
                ''
            }
        )),

    [string]
    $GitHubToken = (property GitHubToken ''), # retrieves from Environment variable

    [string]
    $ReleaseBranch = (property ReleaseBranch 'master')
)

task Publish_release_to_GitHub -if ($GitHubToken) {

    if ([String]::IsNullOrEmpty($ModuleVersion)) {
        $ModuleInfo = Import-PowerShellDataFile "$OutputDirectory/$ProjectName/*/$ProjectName.psd1" -ErrorAction Stop
        if ($PreReleaseTag = $ModuleInfo.PrivateData.PSData.Prerelease) {
            $ModuleVersion = $ModuleInfo.ModuleVersion + "-" + $PreReleaseTag
        }
        else {
            $ModuleVersion = $ModuleInfo.ModuleVersion
        }
    }
    else {
        # Remove metadata from ModuleVersion
        $ModuleVersion, $BuildMetadata = $ModuleVersion -split '\+', 2
        # Remove Prerelease tag from ModuleVersionFolder
        $ModuleVersionFolder, $PreReleaseTag = $ModuleVersion -split '\-', 2
    }

    # find Module's nupkg
    $PackageToRelease = Get-ChildItem (Join-Path $OutputDirectory "$ProjectName.$ModuleVersion.nupkg")
    $ReleaseTag = "v$ModuleVersion"

    Write-Build DarkGray "About to release $PackageToRelease v$ModuleVersion"
    $remoteURL = git remote get-url origin

    if ($remoteURL -notMatch 'github') {
        return
    }

    # find owner repository / remote
    $Repo = GetHumanishRepositoryDetails -RemoteUrl $remoteURL

    # Prerelease label?
    if ($PreReleaseTag) {
        $Prerelease = $true
    }

    # compile changelog for that version
    if (!(Split-Path $ChangelogPath -isAbsolute)) {
        $ChangelogPath = Join-Path $BuildRoot $ChangelogPath | Convert-Path
    }

    # Parse the Changelog and extract unreleased
    if ((Get-Content -raw $ChangelogPath -ErrorAction SilentlyContinue) -match '\[Unreleased\](?<changeLog>[.\s\w\W]*)\n## \[') {
        $ChangeLog = $matches.ChangeLog
    }
    else {
        $ChangeLog = Get-Content -raw $ChangelogPath -ErrorAction SilentlyContinue
    }

    # if you want to create the tag on /release/v$ModuleVersion branch (default to master)
    $ReleaseBranch = $ExecutionContext.InvokeCommand.ExpandString($ReleaseBranch)

    $releaseParams = @{
        Owner       = $Repo.Owner
        Repository  = $Repo.Repository
        Tag         = $ReleaseTag
        ReleaseName = $ReleaseTag
        Branch      = $ReleaseBranch
        AssetPath   = $PackageToRelease
        Prerelease  = [bool]($PreReleaseTag)
        Description = $ChangeLog
        GitHubToken = $GitHubToken
    }
    $APIResponse = Publish-GitHubRelease @releaseParams
    Write-Build Green "Release Created. Follow the link -> $($APIResponse.html_url)"
}

# task Publish_nupkg_to_GitHub_feed {

# }


# function GetDescriptionFromChangelog
# {
# param(
# [Parameter(Mandatory)]
# [string]
# $ChangelogPath
# )

# $lines = Get-Content -Path $ChangelogPath
# # First two lines are the title and newline
# # Third looks like '## vX.Y.Z-releasetag'
# $sb = [System.Text.StringBuilder]::new($lines[2])
# # Read through until the next '## vX.Y.Z-releasetag' H2
# for ($i = 3; -not $lines[$i].StartsWith('## '); $i++)
# {
# $null = $sb.Append("`n").Append($lines[$i])
# }

# return $sb.ToString()
# }

# $tag = "v$Version"

# $releaseParams = @{
# Owner = $TargetFork
# Repository = $Repository
# Tag = $tag
# ReleaseName = $tag
# Branch = "release/$Version"
# AssetPath = $AssetPath
# Prerelease = [bool]($Version.PreReleaseLabel)
# Description = GetDescriptionFromChangelog -ChangelogPath $ChangelogPath
# GitHubToken = $GitHubToken
# }
# Publish-GitHubRelease @releaseParams

# from https://github.com/PowerShell/vscode-powershell/blob/master/tools/GitHubTools.psm1
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
function Publish-GitHubRelease {
    param(
        [Parameter(Mandatory)]
        [string]
        $Owner,

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

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

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

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

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

        [Parameter()]
        [Alias('Branch', 'Commit')]
        [string]
        $Commitish,

        [Parameter()]
        [string[]]
        $AssetPath,

        [switch]
        $Draft,

        [switch]
        $Prerelease
    )

    $restParams = @{
        tag_name   = $Tag
        name       = $ReleaseName
        body       = $Description
        draft      = [bool]$Draft
        prerelease = [bool]$Prerelease
    }

    if ($Commitish) {
        $restParams.target_commitish = $Commitish
    }

    $restBody = ConvertTo-Json -InputObject $restParams
    $uri = "https://api.github.com/repos/$Owner/$Repository/releases"
    $headers = @{
        Accept        = 'application/vnd.github.v3+json'
        Authorization = "token $GitHubToken"
    }

    $response = Invoke-RestMethod -Method Post -Uri $uri -Body $restBody -Headers $headers

    $releaseId = $response.id
    $assetBaseUri = "https://uploads.github.com/repos/$Owner/$Repository/releases/$releaseId/assets"
    foreach ($asset in $AssetPath) {
        $extension = [System.IO.Path]::GetExtension($asset)
        $fileName = [uri]::EscapeDataString([System.IO.Path]::GetFileName($asset))
        $contentType = 'text/plain'
        switch ($extension) {
            { $_ -in '.zip', '.vsix', 'nupkg' } {
                $contentType = 'application/zip'
                break
            }

            '.json' {
                $contentType = 'application/json'
                break
            }
        }

        $assetUri = "${assetBaseUri}?name=$fileName"
        $headers = @{
            Authorization = "token $GitHubToken"
        }
        # This can be very slow, but it does work
        $null = Invoke-RestMethod -Method Post -Uri $assetUri -InFile $asset -ContentType $contentType -Headers $headers
    }

    return $response
}

# from https://github.com/PowerShell/vscode-powershell/blob/master/tools/GitHubTools.psm1
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
filter GetHumanishRepositoryDetails {
    param(
        [string]
        $RemoteUrl
    )

    if ($RemoteUrl.EndsWith('.git')) {
        $RemoteUrl = $RemoteUrl.Substring(0, $RemoteUrl.Length - 4)
    }
    else {
        $RemoteUrl = $RemoteUrl.Trim('/')
    }

    $lastSlashIdx = $RemoteUrl.LastIndexOf('/')
    $repository = $RemoteUrl.Substring($lastSlashIdx + 1)
    $secondLastSlashIdx = $RemoteUrl.LastIndexOfAny(('/', ':'), $lastSlashIdx - 1)
    $Owner = $RemoteUrl.Substring($secondLastSlashIdx + 1, $lastSlashIdx - $secondLastSlashIdx - 1)

    return @{
        Owner      = $Owner
        Repository = $repository
    }
}