262 lines
10 KiB
YAML
262 lines
10 KiB
YAML
name: Publish to PowerShell Gallery
|
|
|
|
on:
|
|
pull_request:
|
|
types: [closed]
|
|
branches: [main]
|
|
|
|
jobs:
|
|
build:
|
|
if: github.event.pull_request.merged == true
|
|
runs-on: powershell-linux
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Verify host prerequisites (pwsh, dotnet)
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$missing = @()
|
|
if (-not (Get-Command pwsh -ErrorAction SilentlyContinue)) { $missing += 'pwsh' }
|
|
if (-not (Get-Command dotnet -ErrorAction SilentlyContinue)) { $missing += 'dotnet' }
|
|
if ($missing.Count -gt 0) {
|
|
throw "Host runner is missing required tool(s): $($missing -join ', '). Provision them on the runner host."
|
|
}
|
|
Write-Host ("pwsh: " + (pwsh -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'))
|
|
Write-Host ("dotnet: " + (dotnet --version))
|
|
|
|
- name: Build and test module
|
|
shell: pwsh
|
|
run: ./build.ps1 -RunTests
|
|
|
|
- name: Validate module manifest
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$manifestPath = Join-Path $PWD 'Module/PSInfisicalAPI/PSInfisicalAPI.psd1'
|
|
$manifest = Test-ModuleManifest -Path $manifestPath
|
|
Write-Host "Manifest OK: $($manifest.Name) $($manifest.Version)"
|
|
|
|
- name: Upload module artifact
|
|
uses: christopherhx/gitea-upload-artifact@v4
|
|
with:
|
|
name: PSInfisicalAPI-module
|
|
path: Module/PSInfisicalAPI
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
release:
|
|
needs: build
|
|
if: ${{ success() && github.event.pull_request.merged == true }}
|
|
runs-on: powershell-linux
|
|
outputs:
|
|
version: ${{ steps.meta.outputs.version }}
|
|
tag: ${{ steps.meta.outputs.tag }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Verify host prerequisites (pwsh)
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
if (-not (Get-Command pwsh -ErrorAction SilentlyContinue)) {
|
|
throw "Host runner is missing required tool: pwsh. Provision it on the runner host."
|
|
}
|
|
Write-Host ("pwsh: " + (pwsh -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'))
|
|
|
|
- name: Download module artifact
|
|
uses: christopherhx/gitea-download-artifact@v4
|
|
with:
|
|
name: PSInfisicalAPI-module
|
|
path: Module/PSInfisicalAPI
|
|
|
|
- name: Resolve module version and tag
|
|
id: meta
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$manifestPath = Join-Path $PWD 'Module/PSInfisicalAPI/PSInfisicalAPI.psd1'
|
|
$manifest = Test-ModuleManifest -Path $manifestPath
|
|
$version = $manifest.Version.ToString()
|
|
$tag = $version
|
|
Write-Host "Module version: $version"
|
|
Write-Host "Release tag: $tag"
|
|
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
|
|
- name: Package module as release asset
|
|
shell: pwsh
|
|
env:
|
|
VERSION: ${{ steps.meta.outputs.version }}
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$zipPath = Join-Path $PWD "PSInfisicalAPI-$($env:VERSION).zip"
|
|
if (Test-Path $zipPath) { Remove-Item $zipPath -Force }
|
|
Compress-Archive -Path 'Module/PSInfisicalAPI/*' -DestinationPath $zipPath -Force
|
|
Write-Host "Created: $zipPath ($([math]::Round((Get-Item $zipPath).Length / 1KB, 1)) KB)"
|
|
|
|
- name: Create Gitea release
|
|
shell: pwsh
|
|
env:
|
|
GITEA_TOKEN: ${{ github.token }}
|
|
API_URL: ${{ github.api_url }}
|
|
REPO: ${{ github.repository }}
|
|
TAG: ${{ steps.meta.outputs.tag }}
|
|
VERSION: ${{ steps.meta.outputs.version }}
|
|
COMMIT_SHA: ${{ github.sha }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
|
SERVER_URL: ${{ github.server_url }}
|
|
RUN_ID: ${{ github.run_id }}
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
if ([string]::IsNullOrWhiteSpace($env:GITEA_TOKEN)) {
|
|
throw "github.token is not available; cannot call the Gitea release API."
|
|
}
|
|
|
|
$shortSha = $env:COMMIT_SHA.Substring(0, [Math]::Min(12, $env:COMMIT_SHA.Length))
|
|
$buildUtc = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
|
|
$runUrl = "$($env:SERVER_URL)/$($env:REPO)/actions/runs/$($env:RUN_ID)"
|
|
$prUrl = "$($env:SERVER_URL)/$($env:REPO)/pulls/$($env:PR_NUMBER)"
|
|
|
|
$changelogSection = ''
|
|
if (Test-Path 'CHANGELOG.md') {
|
|
$lines = [System.IO.File]::ReadAllLines('CHANGELOG.md')
|
|
$start = -1; $end = $lines.Length
|
|
for ($i = 0; $i -lt $lines.Length; $i++) {
|
|
if ($lines[$i] -match "^##\s+$([regex]::Escape($env:VERSION))\s*$") { $start = $i + 1; continue }
|
|
if ($start -ge 0 -and $lines[$i] -match '^##\s+') { $end = $i; break }
|
|
}
|
|
if ($start -ge 0) {
|
|
$changelogSection = ($lines[$start..($end - 1)] -join "`n").Trim()
|
|
}
|
|
}
|
|
|
|
$body = @"
|
|
**PSInfisicalAPI $($env:VERSION)**
|
|
|
|
| Field | Value |
|
|
| --- | --- |
|
|
| Version | ``$($env:VERSION)`` |
|
|
| Tag | ``$($env:TAG)`` |
|
|
| Commit | [``$shortSha``]($($env:SERVER_URL)/$($env:REPO)/commit/$($env:COMMIT_SHA)) |
|
|
| Built (UTC) | $buildUtc |
|
|
| Merged PR | [#$($env:PR_NUMBER) $($env:PR_TITLE)]($prUrl) by @$($env:PR_AUTHOR) |
|
|
| Workflow run | [$($env:RUN_ID)]($runUrl) |
|
|
|
|
## Changes
|
|
$(if ($changelogSection) { $changelogSection } else { '_No CHANGELOG section found for this version._' })
|
|
|
|
## Install
|
|
``````powershell
|
|
Install-Module -Name PSInfisicalAPI -RequiredVersion $($env:VERSION) -Scope CurrentUser
|
|
``````
|
|
"@
|
|
|
|
$headers = @{
|
|
Authorization = "token $($env:GITEA_TOKEN)"
|
|
Accept = 'application/json'
|
|
}
|
|
$createUri = "$($env:API_URL)/repos/$($env:REPO)/releases"
|
|
|
|
$existing = $null
|
|
try {
|
|
$existing = Invoke-RestMethod -Method Get -Headers $headers `
|
|
-Uri "$createUri/tags/$($env:TAG)" -ErrorAction Stop
|
|
} catch {
|
|
if ($_.Exception.Response.StatusCode.value__ -ne 404) { throw }
|
|
}
|
|
if ($existing) {
|
|
Write-Host "Release tag '$($env:TAG)' already exists (id=$($existing.id)); skipping release creation."
|
|
return
|
|
}
|
|
|
|
$payload = @{
|
|
tag_name = $env:TAG
|
|
target_commitish = $env:COMMIT_SHA
|
|
name = "PSInfisicalAPI $($env:VERSION)"
|
|
body = $body
|
|
draft = $false
|
|
prerelease = $false
|
|
} | ConvertTo-Json -Depth 4
|
|
|
|
$release = Invoke-RestMethod -Method Post -Uri $createUri -Headers $headers `
|
|
-ContentType 'application/json' -Body $payload
|
|
Write-Host "Created release id=$($release.id) at $($release.html_url)"
|
|
|
|
$assetPath = Join-Path $PWD "PSInfisicalAPI-$($env:VERSION).zip"
|
|
$uploadUri = "$createUri/$($release.id)/assets?name=PSInfisicalAPI-$($env:VERSION).zip"
|
|
$fileBytes = [System.IO.File]::ReadAllBytes($assetPath)
|
|
Invoke-RestMethod -Method Post -Uri $uploadUri -Headers $headers `
|
|
-ContentType 'application/zip' -Body $fileBytes | Out-Null
|
|
Write-Host "Uploaded asset: PSInfisicalAPI-$($env:VERSION).zip"
|
|
|
|
publish:
|
|
needs: release
|
|
if: ${{ success() && github.event.pull_request.merged == true }}
|
|
runs-on: powershell-linux
|
|
steps:
|
|
- name: Verify host prerequisites (pwsh)
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
if (-not (Get-Command pwsh -ErrorAction SilentlyContinue)) {
|
|
throw "Host runner is missing required tool: pwsh. Provision it on the runner host."
|
|
}
|
|
Write-Host ("pwsh: " + (pwsh -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'))
|
|
|
|
- name: Download module artifact
|
|
uses: christopherhx/gitea-download-artifact@v4
|
|
with:
|
|
name: PSInfisicalAPI-module
|
|
path: Module/PSInfisicalAPI
|
|
|
|
- name: Bootstrap Microsoft.PowerShell.PSResourceGet
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
if (-not (Get-Module -ListAvailable -Name Microsoft.PowerShell.PSResourceGet)) {
|
|
throw "Microsoft.PowerShell.PSResourceGet is not installed on the host runner. Provision it (Install-Module Microsoft.PowerShell.PSResourceGet -Scope AllUsers)."
|
|
}
|
|
Import-Module Microsoft.PowerShell.PSResourceGet -ErrorAction Stop
|
|
Set-PSResourceRepository -Name PSGallery -Trusted -ApiVersion v2
|
|
Get-PSResourceRepository -Name PSGallery | Format-Table Name,Uri,Trusted,ApiVersion
|
|
|
|
- name: Verify PowerShell Gallery API key is configured
|
|
shell: pwsh
|
|
env:
|
|
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
|
|
run: |
|
|
if ([string]::IsNullOrWhiteSpace($env:PSGALLERY_API_KEY)) {
|
|
throw "Repository secret 'PSGALLERY_API_KEY' is not configured."
|
|
}
|
|
|
|
- name: Re-validate downloaded module manifest
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$manifestPath = Join-Path $PWD 'Module/PSInfisicalAPI/PSInfisicalAPI.psd1'
|
|
$manifest = Test-ModuleManifest -Path $manifestPath
|
|
Write-Host "Manifest OK: $($manifest.Name) $($manifest.Version)"
|
|
|
|
- name: Publish to PowerShell Gallery
|
|
shell: pwsh
|
|
env:
|
|
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$moduleDir = Join-Path $PWD 'Module/PSInfisicalAPI'
|
|
Write-Host "Publishing module from: $moduleDir"
|
|
Publish-PSResource `
|
|
-Path $moduleDir `
|
|
-Repository PSGallery `
|
|
-ApiKey $env:PSGALLERY_API_KEY `
|
|
-Verbose
|