Files
git.stella-ops.org/devops/ci-local/run-act.ps1
2026-02-01 21:37:40 +02:00

163 lines
3.8 KiB
PowerShell

<#
.SYNOPSIS
Run Gitea CI workflows locally using act.
.DESCRIPTION
PowerShell wrapper around nektos/act for local CI execution.
Builds the CI Docker image if needed, ensures .env.local exists,
and invokes act with the correct arguments.
.PARAMETER Workflow
Workflow file name (with or without .yml) under .gitea/workflows/.
.PARAMETER Job
Run only a specific job within the workflow.
.PARAMETER List
List all available workflow jobs without running them.
.PARAMETER DryRun
Dry-run mode (-n). Shows what would execute without running.
.PARAMETER Event
Event type to simulate: pull_request (default) or push.
.PARAMETER Rebuild
Force rebuild of the CI Docker image.
.PARAMETER ActVerbose
Enable verbose act output.
.EXAMPLE
.\run-act.ps1 -List
.\run-act.ps1 -Workflow test-matrix -DryRun
.\run-act.ps1 -Workflow build-test-deploy -Job build
.\run-act.ps1 -Event push -Workflow release-validation
#>
[CmdletBinding()]
param(
[string]$Workflow,
[string]$Job,
[switch]$List,
[switch]$DryRun,
[ValidateSet('pull_request', 'push')]
[string]$Event = 'pull_request',
[switch]$Rebuild,
[switch]$ActVerbose
)
$ErrorActionPreference = 'Stop'
# Resolve paths
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RepoRoot = (Resolve-Path "$ScriptDir\..\..").Path
$CiLocalDir = $ScriptDir
$CiImage = 'stellaops-ci:local'
$Dockerfile = Join-Path $RepoRoot 'devops\docker\Dockerfile.ci'
# ---- Prerequisite checks ----
# Docker
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
Write-Error "Docker is not installed or not in PATH."
exit 1
}
$ErrorActionPreference = 'Continue'
$null = docker info 2>$null
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE -ne 0) {
Write-Error "Docker is not running. Start Docker Desktop and try again."
exit 1
}
# act
if (-not (Get-Command act -ErrorAction SilentlyContinue)) {
Write-Error "act is not installed. Install with: choco install act-cli"
exit 1
}
# ---- Build CI image if needed ----
docker image inspect $CiImage 2>&1 | Out-Null
$imageExists = $LASTEXITCODE -eq 0
if ($Rebuild -or -not $imageExists) {
Write-Host "[ci-local] Building CI image $CiImage ..." -ForegroundColor Cyan
docker build -t $CiImage -f $Dockerfile $RepoRoot
if ($LASTEXITCODE -ne 0) {
Write-Error "CI image build failed."
exit 1
}
}
# ---- Ensure .env.local exists ----
$envLocal = Join-Path $CiLocalDir '.env.local'
$envTemplate = Join-Path $CiLocalDir '.env.local.template'
if (-not (Test-Path $envLocal)) {
Write-Host "[ci-local] Creating .env.local from template ..." -ForegroundColor Yellow
Copy-Item $envTemplate $envLocal
}
# ---- Assemble act arguments ----
$actArgs = @()
# List mode
if ($List) {
$actArgs += '-l'
Push-Location $RepoRoot
try { act @actArgs }
finally { Pop-Location }
exit $LASTEXITCODE
}
# Workflow
if ($Workflow) {
$wfFile = $Workflow
if (-not $wfFile.EndsWith('.yml')) { $wfFile = "$wfFile.yml" }
$wfPath = Join-Path $RepoRoot ".gitea\workflows\$wfFile"
if (-not (Test-Path $wfPath)) {
Write-Error "Workflow not found: $wfPath"
exit 1
}
$actArgs += '-W', $wfPath
}
# Job filter
if ($Job) {
$actArgs += '-j', $Job
}
# Event file
$eventMap = @{
'pull_request' = Join-Path $CiLocalDir 'events\pull-request.json'
'push' = Join-Path $CiLocalDir 'events\push.json'
}
$eventFile = $eventMap[$Event]
if (Test-Path $eventFile) {
$actArgs += '--eventpath', $eventFile
}
# Dry run
if ($DryRun) {
$actArgs += '-n'
}
# Verbose
if ($ActVerbose) {
$actArgs += '--verbose'
}
# ---- Run act ----
Write-Host "[ci-local] act $($actArgs -join ' ')" -ForegroundColor Cyan
Push-Location $RepoRoot
try {
act @actArgs
exit $LASTEXITCODE
}
finally {
Pop-Location
}