module/artifact.psm1

#Requires -PSEdition Core
#Requires -Version 7.2
Import-Module -Name (
    @(
        'nodejs-invoke.psm1',
        'utility.psm1'
    ) |
        ForEach-Object -Process { Join-Path -Path $PSScriptRoot -ChildPath $_ }
) -Prefix 'GitHubActions' -Scope 'Local'
<#
.SYNOPSIS
GitHub Actions - Export Artifact
.DESCRIPTION
Export artifact to persist data and/or share with another job in the same workflow.
.PARAMETER Name
Artifact name.
.PARAMETER Path
Absolute and/or relative path to the file that need to export as artifact.
.PARAMETER LiteralPath
Absolute and/or relative literal path to the file that need to export as artifact.
.PARAMETER BaseRoot
A (literal) path that denote the base root directory of the files for control files structure.
.PARAMETER ContinueOnIssue
Whether the export should continue in the event of files fail to export; If not set and issue is encountered, export will stop and queued files will not export; The partial artifact availables which include files up until the issue; If set and issue is encountered, the issue file will ignore and skip, and queued files will still export; The partial artifact availables which include everything but exclude issue files.
.PARAMETER RetentionTime
Duration of artifact expire, by days.
.OUTPUTS
[PSCustomObject] Exported artifact's metadata.
#>

Function Export-Artifact {
    [CmdletBinding(DefaultParameterSetName = 'Path', HelpUri = 'https://github.com/hugoalh-studio/ghactions-toolkit-powershell/wiki/api_function_export-githubactionsartifact#Export-GitHubActionsArtifact')]
    [OutputType([PSCustomObject])]
    Param (
        [Parameter(Mandatory = $True, Position = 0, ValueFromPipelineByPropertyName = $True)][ValidateScript({ Test-ArtifactName -InputObject $_ }, ErrorMessage = '`{0}` is not a valid GitHub Actions artifact name!')][String]$Name,
        [Parameter(Mandatory = $True, ParameterSetName = 'Path', Position = 1, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)][SupportsWildcards()][Alias('File', 'Files', 'Paths')][String[]]$Path,
        [Parameter(Mandatory = $True, ParameterSetName = 'LiteralPath', ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)][Alias('LiteralFile', 'LiteralFiles', 'LiteralPaths', 'LP', 'PSPath', 'PSPaths')][String[]]$LiteralPath,
        [Parameter(ValueFromPipelineByPropertyName = $True)][ValidateScript({ [System.IO.Path]::IsPathRooted($_) -and (Test-Path -LiteralPath $_ -PathType 'Container') }, ErrorMessage = '`{0}` is not an exist and valid GitHub Actions artifact base root!')][Alias('Root')][String]$BaseRoot = $Env:GITHUB_WORKSPACE,
        [Parameter(ValueFromPipelineByPropertyName = $True)][Alias('ContinueOnError')][Switch]$ContinueOnIssue,
        [Parameter(ValueFromPipelineByPropertyName = $True)][ValidateRange(1, 90)][Alias('RetentionDay')][Byte]$RetentionTime
    )
    Begin {
        [Boolean]$NoOperation = $False# When the requirements are not fulfill, only stop this function but not others.
        If (!(Test-GitHubActionsEnvironment -Artifact)) {
            Write-Error -Message 'Unable to get GitHub Actions artifact resources!' -Category 'ResourceUnavailable'
            $NoOperation = $True
        }
    }
    Process {
        If ($NoOperation) {
            Return
        }
        Switch ($PSCmdlet.ParameterSetName) {
            'LiteralPath' {
                [String[]]$PathsProceed = $LiteralPath |
                    ForEach-Object -Process { [System.IO.Path]::IsPathRooted($_) ? $_ : (Join-Path -Path $BaseRoot -ChildPath $_) }
            }
            'Path' {
                [String[]]$PathsProceed = @()
                ForEach ($Item In $Path) {
                    Try {
                        $PathsProceed += Resolve-Path -Path ([System.IO.Path]::IsPathRooted($Item) ? $Item : (Join-Path -Path $BaseRoot -ChildPath $Item))
                    }
                    Catch {
                        $PathsProceed += $Item
                    }
                }
            }
        }
        [Hashtable]$InputObject = @{
            Name = $Name
            Path = $PathsProceed
            BaseRoot = $BaseRoot
            ContinueOnIssue = $ContinueOnIssue.IsPresent
        }
        If ($RetentionTime -igt 0) {
            $InputObject.RetentionTIme = $RetentionTime
        }
        Invoke-GitHubActionsNodeJsWrapper -Path 'artifact\upload.js' -InputObject ([PSCustomObject]$InputObject) |
            Write-Output
    }
}
Set-Alias -Name 'Save-Artifact' -Value 'Export-Artifact' -Option 'ReadOnly' -Scope 'Local'
<#
.SYNOPSIS
GitHub Actions - Import Artifact
.DESCRIPTION
Import artifact that shared data from previous job in the same workflow.
.PARAMETER Name
Artifact name.
.PARAMETER CreateSubfolder
Create a subfolder with artifact name and put data into here.
.PARAMETER All
Import all artifacts that shared data from previous job in the same workflow; Always create subfolder.
.PARAMETER Destination
Artifact destination.
.OUTPUTS
[PSCustomObject] Imported artifact's metadata.
[PSCustomObject[]] Imported artifacts' metadata.
#>

Function Import-Artifact {
    [CmdletBinding(DefaultParameterSetName = 'Single', HelpUri = 'https://github.com/hugoalh-studio/ghactions-toolkit-powershell/wiki/api_function_import-githubactionsartifact#Import-GitHubActionsArtifact')]
    [OutputType([PSCustomObject[]], ParameterSetName = 'All')]
    [OutputType([PSCustomObject], ParameterSetName = 'Single')]
    Param (
        [Parameter(Mandatory = $True, ParameterSetName = 'Single', Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)][ValidateScript({ Test-ArtifactName -InputObject $_ }, ErrorMessage = '`{0}` is not a valid GitHub Actions artifact name!')][String]$Name,
        [Parameter(ParameterSetName = 'Single', ValueFromPipelineByPropertyName = $True)][Switch]$CreateSubfolder,
        [Parameter(Mandatory = $True, ParameterSetName = 'All')][Switch]$All,
        [Parameter(ValueFromPipelineByPropertyName = $True)][Alias('Dest', 'Target')][String]$Destination = $Env:GITHUB_WORKSPACE
    )
    Begin {
        [Boolean]$NoOperation = $False# When the requirements are not fulfill, only stop this function but not others.
        If (!(Test-GitHubActionsEnvironment -Artifact)) {
            Write-Error -Message 'Unable to get GitHub Actions artifact resources!' -Category 'ResourceUnavailable'
            $NoOperation = $True
        }
    }
    Process {
        If ($NoOperation) {
            Return
        }
        Switch ($PSCmdlet.ParameterSetName) {
            'All' {
                Invoke-GitHubActionsNodeJsWrapper -Path 'artifact\download-all.js' -InputObject ([PSCustomObject]@{
                    Destination = $Destination
                }) |
                    Write-Output
            }
            'Single' {
                Invoke-GitHubActionsNodeJsWrapper -Path 'artifact\download.js' -InputObject ([PSCustomObject]@{
                    Name = $Name
                    Destination = $Destination
                    CreateSubfolder = $CreateSubfolder.IsPresent
                }) |
                    Write-Output
            }
        }
    }
}
Set-Alias -Name 'Restore-Artifact' -Value 'Import-Artifact' -Option 'ReadOnly' -Scope 'Local'
<#
.SYNOPSIS
GitHub Actions (Private) - Test Artifact Name
.DESCRIPTION
Test GitHub Actions artifact name whether is valid.
.PARAMETER InputObject
GitHub Actions artifact name that need to test.
.OUTPUTS
[Boolean] Test result.
#>

Function Test-ArtifactName {
    [CmdletBinding()]
    [OutputType([Boolean])]
    Param (
        [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)][Alias('Input', 'Object')][String]$InputObject
    )
    Process {
        (Test-ArtifactPath -InputObject $InputObject) -and $InputObject -imatch '^[^\\/]+$' |
            Write-Output
    }
}
<#
.SYNOPSIS
GitHub Actions (Private) - Test Artifact Path
.DESCRIPTION
Test GitHub Actions artifact path whether is valid.
.PARAMETER InputObject
GitHub Actions artifact path that need to test.
.OUTPUTS
[Boolean] Test result.
#>

Function Test-ArtifactPath {
    [CmdletBinding()]
    [OutputType([Boolean])]
    Param (
        [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)][Alias('Input', 'Object')][String]$InputObject
    )
    Process {
        $InputObject -imatch '^[^":<>|*?\n\r\t]+$' |
            Write-Output
    }
}
Export-ModuleMember -Function @(
    'Export-Artifact',
    'Import-Artifact'
) -Alias @(
    'Restore-Artifact',
    'Save-Artifact'
)