diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index b3ea7cb4..f016bd08 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -1,3 +1,4 @@ self-hosted-runner: labels: - icon-editor-windows + - self-hosted-windows-lv diff --git a/.github/workflows/ci.json b/.github/workflows/ci.json index f87bbe5e..e5450c12 100644 --- a/.github/workflows/ci.json +++ b/.github/workflows/ci.json @@ -46,7 +46,7 @@ { "run": "npm run generate:summary", "env": { - "TEST_RESULTS_GLOB": "test-results/*junit*.xml" + "TEST_RESULTS_GLOBS": "test-results/*junit*.xml" } }, { @@ -83,12 +83,17 @@ { "os": "ubuntu-24.04", "runs-on": "ubuntu-24.04", - "runner_type": "default" + "runner_type": "linux" }, { - "os": "windows-latest", - "runs-on": "windows-latest", + "os": "self-hosted-windows-lv", + "runs-on": "self-hosted-windows-lv", "runner_type": "integration" + }, + { + "os": "self-hosted-windows-lv", + "runs-on": "self-hosted-windows-lv", + "runner_type": "default" } ] } @@ -102,22 +107,22 @@ "uses": "actions/checkout@v4" }, { - "name": "Install PowerShell 7.5.1", - "if": "matrix.os == 'windows-latest'", + "name": "Ensure PowerShell 7.5.1", + "if": "matrix.runner_type != 'linux'", "shell": "pwsh", - "run": "$expectedBuild = '10.0.20348'\n$build = (Get-ComputerInfo).OsVersion\nif ($build -ne $expectedBuild) {\n throw \"Unexpected OS build: $build\"\n}\n$msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi'\n$msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi'\nInvoke-WebRequest -Uri $msiUrl -OutFile $msiPath\n$expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a'\n$actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash\nif ($actualHash -ne $expectedHash) {\n throw \"SHA256 mismatch: $actualHash\"\n}\nStart-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1'\n$version = (pwsh --version).Trim() -replace '^PowerShell '\nif ($version -ne '7.5.1') {\n throw \"PowerShell version $version is not 7.5.1\"\n}\n" + "run": "$required = [Version]'7.5.1'\nif ($PSVersionTable.PSVersion -lt $required) {\n $msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi'\n $msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi'\n Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath\n $expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a'\n $actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash\n if ($actualHash -ne $expectedHash) {\n throw \"SHA256 mismatch: $actualHash\"\n }\n Start-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1'\n}\n$version = (pwsh --version).Trim() -replace '^PowerShell '\nif ([Version]$version -lt $required) {\n throw \"PowerShell version $version is less than $required\"\n}\n" }, { "name": "Capture setup info", "shell": "pwsh", - "run": "$data = [ordered]@{\n 'Current runner version' = $env:RUNNER_VERSION\n 'Runner Image' = $env:ImageOS\n 'ImageVersion' = $env:ImageVersion\n 'RUNNER_NAME' = $env:RUNNER_NAME\n 'RUNNER_OS' = $env:RUNNER_OS\n 'RUNNER_ARCH' = $env:RUNNER_ARCH\n}\n$file = \"setup-info-${{ matrix.os }}.md\"\n\"was captured from the set up job.\" | Out-File -FilePath $file -Encoding utf8\nforeach ($k in $data.Keys) {\n if ($data[$k]) {\n \"${k}: $($data[$k])\" | Out-File -FilePath $file -Encoding utf8 -Append\n }\n}\n" + "run": "$data = [ordered]@{\n 'Current runner version' = $env:RUNNER_VERSION\n 'Runner Image' = $env:ImageOS\n 'ImageVersion' = $env:ImageVersion\n 'RUNNER_NAME' = $env:RUNNER_NAME\n 'RUNNER_OS' = $env:RUNNER_OS\n 'RUNNER_ARCH' = $env:RUNNER_ARCH\n}\n$file = \"setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md\"\n\"was captured from the set up job.\" | Out-File -FilePath $file -Encoding utf8\nforeach ($k in $data.Keys) {\n if ($data[$k]) {\n \"${k}: $($data[$k])\" | Out-File -FilePath $file -Encoding utf8 -Append\n }\n}\n" }, { "uses": "actions/upload-artifact@v4", "if": "always()", "with": { - "name": "setup-info-${{ matrix.os }}", - "path": "setup-info-${{ matrix.os }}.md" + "name": "setup-info-${{ matrix.os }}-${{ matrix.runner_type }}", + "path": "setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md" } }, { @@ -139,7 +144,7 @@ "uses": "actions/upload-artifact@v4", "if": "always()", "with": { - "name": "pester-junit-${{ matrix.os }}", + "name": "pester-junit-${{ matrix.os }}-${{ matrix.runner_type }}", "path": "pester-results/pester-junit.xml", "if-no-files-found": "error" } @@ -152,7 +157,7 @@ "ps-ci" ], "runs-on": "ubuntu-24.04", - "if": "always()", + "if": "(success() || failure()) && !cancelled()", "steps": [ { "uses": "actions/checkout@v4" @@ -184,7 +189,7 @@ "TEST_RESULTS_GLOBS": "downloaded/test-results/**/*junit*.xml\ndownloaded/pester-junit-*/pester-junit.xml\n", "REQ_MAPPING_FILE": "requirements.json", "DISPATCHER_REGISTRY": "dispatchers.json", - "EVIDENCE_DIR": "test-screenshots" + "EVIDENCE_DIR": "downloaded/evidence" } }, { diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c663d79..c0dc9356 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,19 +25,19 @@ jobs: - run: npm run derive:registry - run: npm run generate:summary env: - TEST_RESULTS_GLOB: test-results/*junit*.xml + TEST_RESULTS_GLOBS: test-results/*junit*.xml - uses: actions/upload-artifact@v4 - if: always() + if: ${{ (success() || failure()) && !cancelled() }} with: name: traceability path: ${{ env.ARTIFACT_DIR }}/traceability.* - uses: actions/upload-artifact@v4 - if: always() + if: ${{ (success() || failure()) && !cancelled() }} with: name: action-docs path: ${{ env.ARTIFACT_DIR }}/action-docs.* - uses: actions/upload-artifact@v4 - if: always() + if: ${{ (success() || failure()) && !cancelled() }} with: name: evidence path: ${{ env.ARTIFACT_DIR }}/evidence/** @@ -49,31 +49,37 @@ jobs: include: - os: ubuntu-24.04 runs-on: ubuntu-24.04 - runner_type: default - - os: windows-latest - runs-on: windows-latest + runner_type: linux + - os: self-hosted-windows-lv + runs-on: self-hosted-windows-lv runner_type: integration + - os: self-hosted-windows-lv + runs-on: self-hosted-windows-lv + runner_type: default runs-on: ${{ matrix.runs-on }} env: RUNNER_TYPE: ${{ matrix.runner_type }} steps: - uses: actions/checkout@v4 - - name: Install PowerShell 7.5.1 - if: matrix.os == 'windows-latest' + - name: Ensure PowerShell 7.5.1 + if: matrix.runner_type != 'linux' shell: pwsh run: | - $msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi' - $msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi' - Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath - $expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a' - $actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash - if ($actualHash -ne $expectedHash) { - throw "SHA256 mismatch: $actualHash" + $required = [Version]'7.5.1' + if ($PSVersionTable.PSVersion -lt $required) { + $msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi' + $msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi' + Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath + $expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a' + $actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash + if ($actualHash -ne $expectedHash) { + throw "SHA256 mismatch: $actualHash" + } + Start-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1' } - Start-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1' $version = (pwsh --version).Trim() -replace '^PowerShell ' - if ($version -ne '7.5.1') { - throw "PowerShell version $version is not 7.5.1" + if ([Version]$version -lt $required) { + throw "PowerShell version $version is less than $required" } - name: Capture setup info shell: pwsh @@ -86,7 +92,7 @@ jobs: 'RUNNER_OS' = $env:RUNNER_OS 'RUNNER_ARCH' = $env:RUNNER_ARCH } - $file = "setup-info-${{ matrix.os }}.md" + $file = "setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md" "was captured from the set up job." | Out-File -FilePath $file -Encoding utf8 foreach ($k in $data.Keys) { if ($data[$k]) { @@ -94,10 +100,10 @@ jobs: } } - uses: actions/upload-artifact@v4 - if: always() + if: ${{ (success() || failure()) && !cancelled() }} with: - name: setup-info-${{ matrix.os }} - path: setup-info-${{ matrix.os }}.md + name: setup-info-${{ matrix.os }}-${{ matrix.runner_type }} + path: setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md - name: Install Pester shell: pwsh run: | @@ -112,21 +118,23 @@ jobs: if (Test-Path "tests/pester") { $cfg = New-PesterConfiguration $cfg.Run.Path = './tests/pester' - $cfg.TestResult.Enabled = $false + $cfg.TestResult.Enabled = $true + $cfg.TestResult.OutputFormat = 'JUnitXml' + $cfg.TestResult.OutputPath = 'pester-results/pester-junit.xml' $cfg.Run.Exit = $true Invoke-Pester -Configuration $cfg } - uses: actions/upload-artifact@v4 - if: always() + if: ${{ (success() || failure()) && !cancelled() }} with: - name: pester-junit-${{ matrix.os }} + name: pester-junit-${{ matrix.os }}-${{ matrix.runner_type }} path: pester-results/pester-junit.xml if-no-files-found: error report: needs: [node-ci, ps-ci] runs-on: ubuntu-24.04 - if: always() + if: ${{ (success() || failure()) && !cancelled() }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -145,5 +153,5 @@ jobs: downloaded/pester-junit-*/pester-junit.xml REQ_MAPPING_FILE: requirements.json DISPATCHER_REGISTRY: dispatchers.json - EVIDENCE_DIR: test-screenshots + EVIDENCE_DIR: downloaded/evidence - run: npx tsx scripts/print-pester-traceability.ts >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/missing-in-project-self-hosted.json b/.github/workflows/missing-in-project-self-hosted.json index f15eb060..bebe0dfe 100644 --- a/.github/workflows/missing-in-project-self-hosted.json +++ b/.github/workflows/missing-in-project-self-hosted.json @@ -15,7 +15,7 @@ "uses": "./missing-in-project/action.yml", "with": { "lv_version": "2021", - "arch": "64", + "supported_bitness": "64", "project_file": "scripts/missing-in-project/Missing in Project.lvproj", "relative_path": "scripts/missing-in-project" } diff --git a/.github/workflows/missing-in-project-self-hosted.yml b/.github/workflows/missing-in-project-self-hosted.yml index 37ab7806..e0f8fd3a 100644 --- a/.github/workflows/missing-in-project-self-hosted.yml +++ b/.github/workflows/missing-in-project-self-hosted.yml @@ -12,7 +12,7 @@ jobs: uses: ./missing-in-project/action.yml with: lv_version: '2021' - arch: '64' + supported_bitness: '64' project_file: 'scripts/missing-in-project/Missing in Project.lvproj' relative_path: 'scripts/missing-in-project' - name: Upload missing findings diff --git a/AGENTS.md b/AGENTS.md index 8a86b5fc..f98f4c1f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,9 +3,12 @@ ## Environment Setup - Run `apt-get update && apt-get install -y apt-utils` to ensure required APT utilities are available. - Ensure Node.js 24 or newer is installed (e.g. via the NodeSource setup script). + - Verify with `node --version`. - Install `actionlint` and ensure it is on your `PATH`: - `go install github.com/rhysd/actionlint/cmd/actionlint@latest` + - Verify with `actionlint -version`. - Ensure PowerShell 7.5.1 is installed and accessible. + - Verify with `pwsh --version`. - Linux runners rely on preinstalled `pwsh`. - On Windows Server 2022 (build 10.0.20348), download the MSI and verify its SHA256 checksum before installing: @@ -18,6 +21,10 @@ Remove-Item pwsh.msi ``` - PowerShell 7.5.1 includes native YAML support; external modules such as `powershell-yaml` are no longer required. +- Install NI LabVIEW's command-line interface (g-cli) on Windows runners and ensure it is accessible. + - Verify with `g-cli --version` or `& 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe' --version`. +- Optional: set `LABVIEW_ICON_EDITOR_PATH` if a custom icon editor location is required. + - Verify with `echo $LABVIEW_ICON_EDITOR_PATH` (or `$env:LABVIEW_ICON_EDITOR_PATH` in PowerShell). ## Testing - Run `npm run check:node` to verify Node.js satisfies the required version. diff --git a/README.md b/README.md index c2730c99..d33ca36f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ For setup and action reference, see the [documentation](docs/index.md). The [qui - NI LabVIEW with command-line interface support (g-cli) for LabVIEW-based actions - Supported platforms: Windows for LabVIEW tasks; PowerShell-only scripts also run on macOS and Linux +See [Environment Setup](docs/environment-setup.md) for installation steps and commands to verify each dependency. + ## GitHub Action usage ```yaml @@ -111,6 +113,12 @@ Alternatively, load arguments from a JSON file: pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsFile ./config/run-tests.json ``` +By default the dispatcher ignores unknown parameters and emits a warning. Add `-FailOnUnknown` to treat unexpected parameters as errors: + +```powershell +pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsJson $json -FailOnUnknown +``` + ### Discovering actions List all available actions: @@ -125,6 +133,10 @@ Get details about a specific action: pwsh actions/Invoke-OSAction.ps1 -Describe run-unit-tests ``` +## Runner Types + +Workflows distinguish between standard GitHub-hosted images and integration runners with preinstalled tooling. See [docs/runner-types.md](docs/runner-types.md) for a detailed comparison. + ## Testing Run the JavaScript tests with: diff --git a/actions/Invoke-OSAction.ps1 b/actions/Invoke-OSAction.ps1 index 3dfd31e6..5785670a 100644 --- a/actions/Invoke-OSAction.ps1 +++ b/actions/Invoke-OSAction.ps1 @@ -8,6 +8,7 @@ param( [Parameter()] [ValidateSet('ERROR','WARN','INFO','DEBUG')] [string] $LogLevel = 'INFO', [switch] $DryRun, [switch] $ListActions, + [switch] $FailOnUnknown, [string] $Describe ) @@ -97,8 +98,15 @@ function Show-Description([string]$Name) { # InputArgs: Hashtable of supplied arguments. # FuncName: Target dispatcher function name. # ActionNameForWarn: Action name used when emitting warnings. -# ReturnUnknownParams: If set, returns unknown parameters as well. -function Filter-Args([hashtable]$InputArgs, [string]$FuncName, [string]$ActionNameForWarn, [switch]$ReturnUnknownParams) { +# ReturnUnknownParams: If set, returns unknown parameters and suppresses warnings. +# NoWarn: Suppresses warnings for unknown parameters without returning them. +function Filter-Args( + [hashtable]$InputArgs, + [string]$FuncName, + [string]$ActionNameForWarn, + [switch]$ReturnUnknownParams, + [switch]$NoWarn +) { $cmd = Get-Command $FuncName -ErrorAction Stop # Map each alias to its canonical parameter name for the target function @@ -124,7 +132,9 @@ function Filter-Args([hashtable]$InputArgs, [string]$FuncName, [string]$ActionNa $msg = $null if ($unknown.Count) { $msg = "Ignored unknown parameters for '$ActionNameForWarn': $($unknown -join ', ')" - Write-Warning $msg + if (-not $NoWarn -and -not $ReturnUnknownParams) { + Write-Warning $msg + } } if ($ReturnUnknownParams) { return [pscustomobject]@{ Args = $filtered; UnknownParams = $msg } @@ -132,6 +142,25 @@ function Filter-Args([hashtable]$InputArgs, [string]$FuncName, [string]$ActionNa return $filtered } +# Normalizes a RelativePath value against an optional base directory. +# RelativePath: Path to normalize. +# BaseDirectory: Directory used to resolve the relative path. Defaults to the current location. +function Normalize-RelativePath { + param( + [Parameter(Mandatory)] [string] $RelativePath, + [string] $BaseDirectory + ) + $base = if ($BaseDirectory) { + [System.IO.Path]::GetFullPath($BaseDirectory) + } else { + [System.IO.Directory]::GetCurrentDirectory() + } + $combined = [System.IO.Path]::Combine($base, $RelativePath) + $full = [System.IO.Path]::GetFullPath($combined) + $relative = [System.IO.Path]::GetRelativePath($base, $full) + return [System.IO.Path]::TrimEndingDirectorySeparator($relative) +} + try { # Discovery short-circuits if ($ListActions) { Show-List; exit 0 } @@ -198,7 +227,19 @@ try { Set-LogLevel -Level $LogLevel # Only pass parameters that the adapter actually accepts - $argsHash = Filter-Args -InputArgs $argsHash -FuncName $funcName -ActionNameForWarn $key + $filterResult = Filter-Args -InputArgs $argsHash -FuncName $funcName -ActionNameForWarn $key -ReturnUnknownParams + $argsHash = $filterResult.Args + if ($filterResult.UnknownParams) { + if ($FailOnUnknown) { + throw $filterResult.UnknownParams + } else { + Write-Warning $filterResult.UnknownParams + } + } + + if ($argsHash.ContainsKey('RelativePath')) { + $argsHash['RelativePath'] = Normalize-RelativePath -RelativePath $argsHash['RelativePath'] -BaseDirectory $WorkingDirectory + } if ($WorkingDirectory) { Push-Location -Path $WorkingDirectory } try { diff --git a/actions/OpenSourceActions.psm1 b/actions/OpenSourceActions.psm1 index f893b723..7e0e374f 100644 --- a/actions/OpenSourceActions.psm1 +++ b/actions/OpenSourceActions.psm1 @@ -15,6 +15,9 @@ function Invoke-OpenSourceActionScript { foreach ($seg in $segments) { $scriptPath = [System.IO.Path]::Combine($scriptPath, $seg) } + if ($Arguments.ContainsKey('RelativePath')) { + $Arguments['RelativePath'] = [System.IO.Path]::TrimEndingDirectorySeparator($Arguments['RelativePath']) + } if ($DryRun) { Write-Information "DryRun: & $scriptPath $($Arguments | ConvertTo-Json -Compress)" return 0 @@ -36,7 +39,7 @@ function Invoke-OpenSourceActionScript { # Adds an authentication token to a LabVIEW installation. # MinimumSupportedLVVersion: Minimum LabVIEW version that the project supports. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # DryRun: If set, prints the command instead of executing it. # gcliPath: Optional path prepended to PATH for locating the g CLI. function Invoke-AddTokenToLabVIEW { @@ -61,7 +64,7 @@ function Invoke-AddTokenToLabVIEW { # MinimumSupportedLVVersion: Minimum LabVIEW version that the project supports. # VIP_LVVersion: LabVIEW version used to build the VIPC. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # VIPCPath: Optional path to the VIPC file. # DryRun: If set, prints the command instead of executing it. # gcliPath: Optional path prepended to PATH for locating the g CLI. @@ -91,7 +94,7 @@ function Invoke-ApplyVIPC { # MinimumSupportedLVVersion: Minimum LabVIEW version that the package supports. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). # LabVIEWMinorRevision: Minor revision of LabVIEW used to build the package. -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # VIPBPath: Path to the VIPB build specification file. # Major: Major version component. # Minor: Minor version component. @@ -139,7 +142,7 @@ function Invoke-BuildViPackage { } # Builds the project and records version information. -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # Major: Major version component. # Minor: Minor version component. # Patch: Patch version component. @@ -183,7 +186,7 @@ function Invoke-Build { # Builds a LabVIEW Packed Library using a project and build spec. # MinimumSupportedLVVersion: Minimum LabVIEW version that the library supports. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # LabVIEW_Project: Path to the LabVIEW project file. # Build_Spec: Name of the build specification within the project. # Major: Major version component. @@ -264,7 +267,7 @@ function Invoke-GenerateReleaseNotes { # Lists files referenced in a LabVIEW project that are missing on disk. # LVVersion: LabVIEW version of the project. -# Arch: Target architecture or bitness. +# SupportedBitness: Target LabVIEW bitness (32- or 64-bit). # ProjectFile: Path to the .lvproj file to analyze. # DryRun: If set, prints the command instead of executing it. # gcliPath: Optional path prepended to PATH for locating the g CLI. @@ -272,23 +275,23 @@ function Invoke-MissingInProject { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $LVVersion, - [Parameter(Mandatory)] [string] $Arch, + [Parameter(Mandatory)] [string] $SupportedBitness, [Parameter(Mandatory)] [string] $ProjectFile, [Parameter()] [switch] $DryRun, [Parameter()] [string] $gcliPath ) Write-Information "Executing MissingInProject (DryRun=$DryRun)" $args = @{ - LVVersion = $LVVersion - Arch = $Arch - ProjectFile = $ProjectFile + LVVersion = $LVVersion + SupportedBitness = $SupportedBitness + ProjectFile = $ProjectFile } return Invoke-OpenSourceActionScript -ScriptSegments @('missing-in-project','Invoke-MissingInProjectCLI.ps1') -Arguments $args -DryRun:$DryRun -gcliPath $gcliPath } # Updates display information fields in a VIPB build specification. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # VIPBPath: Path to the VIPB build specification file. # MinimumSupportedLVVersion: Minimum LabVIEW version that the package supports. # LabVIEWMinorRevision: Minor revision of LabVIEW used for the build. @@ -340,7 +343,7 @@ function Invoke-ModifyVIPBDisplayInfo { # Prepares a LabVIEW project for source distribution. # MinimumSupportedLVVersion: Minimum LabVIEW version that the project supports. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # LabVIEW_Project: Path to the LabVIEW project file. # Build_Spec: Name of the build specification within the project. # DryRun: If set, prints the command instead of executing it. @@ -391,7 +394,7 @@ function Invoke-RenameFile { # Restores the Setup LabVIEW source build specification. # MinimumSupportedLVVersion: Minimum LabVIEW version that the project supports. # SupportedBitness: Target LabVIEW bitness (32- or 64-bit). -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # LabVIEW_Project: Path to the LabVIEW project file. # Build_Spec: Name of the build specification within the project. # DryRun: If set, prints the command instead of executing it. @@ -419,7 +422,7 @@ function Invoke-RestoreSetupLVSource { } # Returns a repository to its previous development mode state. -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # DryRun: If set, prints the command instead of executing it. # gcliPath: Optional path prepended to PATH for locating the g CLI. function Invoke-RevertDevelopmentMode { @@ -472,7 +475,7 @@ function Invoke-RunUnitTests { } # Configures the repository for development mode. -# RelativePath: Path to the project root relative to the working directory. +# RelativePath: Normalized path to the project root relative to the working directory. # DryRun: If set, prints the command instead of executing it. # gcliPath: Optional path prepended to PATH for locating the g CLI. function Invoke-SetDevelopmentMode { diff --git a/dispatchers.json b/dispatchers.json index 06691590..a15c1ffb 100644 --- a/dispatchers.json +++ b/dispatchers.json @@ -5,17 +5,17 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the project supports." + "description": "Minimum LabVIEW version that the project supports" }, "RelativePath": { "type": "string", @@ -25,7 +25,7 @@ "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -35,17 +35,17 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the project supports." + "description": "Minimum LabVIEW version that the project supports" }, "RelativePath": { "type": "string", @@ -55,17 +55,17 @@ "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" }, "VIP_LVVersion": { "type": "string", "required": true, - "description": "LabVIEW version used to build the VI Package Configuration." + "description": "LabVIEW version used to build the VIPC" }, "VIPCPath": { "type": "string", "required": false, - "description": "Path to the VI Package Configuration file." + "description": "Optional path to the VIPC file" } } }, @@ -75,52 +75,52 @@ "AuthorName": { "type": "string", "required": true, - "description": "Author name recorded in build metadata." + "description": "Author name recorded in build metadata" }, "Build": { "type": "number", "required": true, - "description": "Build number component." + "description": "Build number component" }, "Commit": { "type": "string", "required": true, - "description": "Commit identifier used for the build metadata." + "description": "Commit identifier used for the build metadata" }, "CompanyName": { "type": "string", "required": true, - "description": "Company name recorded in build metadata." + "description": "Company name recorded in build metadata" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LabVIEWMinorRevision": { "type": "string", "required": true, - "description": "Minor revision of LabVIEW used for the build." + "description": "Minor revision of LabVIEW used for the build" }, "Major": { "type": "number", "required": true, - "description": "Major version component." + "description": "Major version component" }, "Minor": { "type": "number", "required": true, - "description": "Minor version component." + "description": "Minor version component" }, "Patch": { "type": "number", "required": true, - "description": "Patch version component." + "description": "Patch version component" }, "RelativePath": { "type": "string", @@ -135,52 +135,52 @@ "Build": { "type": "number", "required": true, - "description": "Build number component." + "description": "Build number component" }, "Build_Spec": { "type": "string", "required": true, - "description": "Name of the build specification to run." + "description": "Name of the build specification within the project" }, "Commit": { "type": "string", "required": true, - "description": "Commit identifier used for the build metadata." + "description": "Commit identifier used for the build metadata" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LabVIEW_Project": { "type": "string", "required": true, - "description": "Path to the LabVIEW project file." + "description": "Path to the LabVIEW project file" }, "Major": { "type": "number", "required": true, - "description": "Major version component." + "description": "Major version component" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the library supports." + "description": "Minimum LabVIEW version that the library supports" }, "Minor": { "type": "number", "required": true, - "description": "Minor version component." + "description": "Minor version component" }, "Patch": { "type": "number", "required": true, - "description": "Patch version component." + "description": "Patch version component" }, "RelativePath": { "type": "string", @@ -190,7 +190,7 @@ "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -200,52 +200,52 @@ "Build": { "type": "number", "required": true, - "description": "Build number component." + "description": "Build number component" }, "Commit": { "type": "string", "required": true, - "description": "Commit identifier used for the build metadata." + "description": "Commit identifier used for the build metadata" }, "DisplayInformationJSON": { "type": "string", "required": true, - "description": "Path to JSON file containing display information." + "description": "JSON string containing display information for the package" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LabVIEWMinorRevision": { "type": "string", "required": true, - "description": "Minor revision of LabVIEW used to build the package." + "description": "Minor revision of LabVIEW used to build the package" }, "Major": { "type": "number", "required": true, - "description": "Major version component." + "description": "Major version component" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the package supports." + "description": "Minimum LabVIEW version that the package supports" }, "Minor": { "type": "number", "required": true, - "description": "Minor version component." + "description": "Minor version component" }, "Patch": { "type": "number", "required": true, - "description": "Patch version component." + "description": "Patch version component" }, "RelativePath": { "type": "string", @@ -255,17 +255,17 @@ "ReleaseNotesFile": { "type": "string", "required": false, - "description": "Path to the release notes file." + "description": "Optional path to a release notes file" }, "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" }, "VIPBPath": { "type": "string", "required": true, - "description": "Path to the VI Package Build (.vipb) file." + "description": "Path to the VIPB build specification file" } } }, @@ -275,22 +275,22 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the project supports." + "description": "Minimum LabVIEW version that the project supports" }, "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -300,48 +300,48 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "OutputPath": { "type": "string", "required": false, "default": "Tooling/deployment/release_notes.md", - "description": "Path where generated release notes will be written." + "description": "Path where the release notes should be written" } } }, "Invoke-MissingInProject": { - "description": "Lists files referenced in a LabVIEW project that are missing on disk. LVVersion: LabVIEW version of the project. Arch: Target architecture or bitness. ProjectFile: Path to the .lvproj file to analyze. DryRun: If set, prints the command instead of executing it. gcliPath: Optional path prepended to PATH for locating the g CLI.", + "description": "Lists files referenced in a LabVIEW project that are missing on disk. LVVersion: LabVIEW version of the project. SupportedBitness: Target LabVIEW bitness (32- or 64-bit). ProjectFile: Path to the .lvproj file to analyze. DryRun: If set, prints the command instead of executing it. gcliPath: Optional path prepended to PATH for locating the g CLI.", "parameters": { - "Arch": { - "type": "string", - "required": true, - "description": "Target architecture or bitness." - }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LVVersion": { "type": "string", "required": true, - "description": "LabVIEW version of the project." + "description": "LabVIEW version of the project" }, "ProjectFile": { "type": "string", "required": true, - "description": "Path to the LabVIEW project file." + "description": "Path to the" + }, + "SupportedBitness": { + "type": "string", + "required": true, + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -351,52 +351,52 @@ "Build": { "type": "number", "required": true, - "description": "Build number component." + "description": "Build number component" }, "Commit": { "type": "string", "required": true, - "description": "Commit identifier used for the build metadata." + "description": "Commit identifier used for the build metadata" }, "DisplayInformationJSON": { "type": "string", "required": true, - "description": "Path to JSON file containing display information." + "description": "JSON string containing display information for the package" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LabVIEWMinorRevision": { "type": "string", "required": true, - "description": "Minor revision of LabVIEW used for the build." + "description": "Minor revision of LabVIEW used for the build" }, "Major": { "type": "number", "required": true, - "description": "Major version component." + "description": "Major version component" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the package supports." + "description": "Minimum LabVIEW version that the package supports" }, "Minor": { "type": "number", "required": true, - "description": "Minor version component." + "description": "Minor version component" }, "Patch": { "type": "number", "required": true, - "description": "Patch version component." + "description": "Patch version component" }, "RelativePath": { "type": "string", @@ -406,17 +406,17 @@ "ReleaseNotesFile": { "type": "string", "required": false, - "description": "Path to the release notes file." + "description": "Optional path to a release notes file" }, "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" }, "VIPBPath": { "type": "string", "required": true, - "description": "Path to the VI Package Build (.vipb) file." + "description": "Path to the VIPB build specification file" } } }, @@ -426,27 +426,27 @@ "Build_Spec": { "type": "string", "required": true, - "description": "Name of the build specification to run." + "description": "Name of the build specification within the project" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LabVIEW_Project": { "type": "string", "required": true, - "description": "Path to the LabVIEW project file." + "description": "Path to the LabVIEW project file" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the project supports." + "description": "Minimum LabVIEW version that the project supports" }, "RelativePath": { "type": "string", @@ -456,7 +456,7 @@ "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -466,22 +466,22 @@ "CurrentFilename": { "type": "string", "required": true, - "description": "Existing path to the file." + "description": "Existing path to the file" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "NewFilename": { "type": "string", "required": true, - "description": "New path for the file." + "description": "New path for the file" } } }, @@ -491,27 +491,27 @@ "Build_Spec": { "type": "string", "required": true, - "description": "Name of the build specification to run." + "description": "Name of the build specification within the project" }, "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "LabVIEW_Project": { "type": "string", "required": true, - "description": "Path to the LabVIEW project file." + "description": "Path to the LabVIEW project file" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the project supports." + "description": "Minimum LabVIEW version that the project supports" }, "RelativePath": { "type": "string", @@ -521,7 +521,7 @@ "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -531,12 +531,12 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "RelativePath": { "type": "string", @@ -551,17 +551,17 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "WorkingDirectory": { "type": "string", "required": true, - "description": "Path containing the Pester tests to execute." + "description": "Path containing the Pester tests to execute" } } }, @@ -571,22 +571,22 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "MinimumSupportedLVVersion": { "type": "string", "required": true, - "description": "Minimum LabVIEW version that the project supports." + "description": "Minimum LabVIEW version that the project supports" }, "SupportedBitness": { "type": "string", "required": true, - "description": "Target LabVIEW bitness (32- or 64-bit)." + "description": "Target LabVIEW bitness (32- or 64-bit)" } } }, @@ -596,12 +596,12 @@ "DryRun": { "type": "boolean", "required": false, - "description": "If set, prints the command instead of executing it." + "description": "If set, prints the command instead of executing it" }, "gcliPath": { "type": "string", "required": false, - "description": "Path prepended to PATH for locating the g CLI." + "description": "Optional path prepended to PATH for locating the g CLI" }, "RelativePath": { "type": "string", @@ -610,39 +610,14 @@ } } }, - "Run": { - "description": "Runs a helper script from the repository's scripts directory. ScriptSegments: Path segments under the scripts folder that locate the target script. Arguments: Hashtable of arguments forwarded to the script. DryRun: If set, writes the command without executing it. gcliPath: Optional path prepended to PATH for locating the g CLI.", - "parameters": { - "Arguments": { - "type": "string", - "required": true, - "description": "Hashtable of arguments forwarded to the script." - }, - "DryRun": { - "type": "boolean", - "required": false, - "description": "If set, prints the command instead of executing it." - }, - "gcliPath": { - "type": "string", - "required": false, - "description": "Path prepended to PATH for locating the g CLI." - }, - "ScriptSegments": { - "type": "string", - "required": true, - "description": "Path segments under the scripts folder that locate the target script." - } - } - }, - "Set": { + "Set-LogLevel": { "description": "Sets the verbosity for informational and verbose messages. Level: Desired log level (ERROR, WARN, INFO, DEBUG).", "parameters": { "Level": { "type": "string", "required": false, - "description": "Desired log level (ERROR, WARN, INFO, DEBUG)." + "description": "Desired log level (ERROR, WARN, INFO, DEBUG)" } } } -} +} \ No newline at end of file diff --git a/docs/UnifiedDispatcher.md b/docs/UnifiedDispatcher.md index 5c4ccf5c..5956bda1 100644 --- a/docs/UnifiedDispatcher.md +++ b/docs/UnifiedDispatcher.md @@ -34,6 +34,17 @@ Arguments can also be read from a JSON file: pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsFile ./config/run-tests.json -LogLevel INFO ``` +### Argument precedence + +When multiple argument sources are supplied, values are merged in the following order: + +1. `ArgsFile` +2. `ArgsJson` +3. `ArgsHashtable` +4. dispatcher switches (for example, `-DryRun`) + +Later entries override earlier ones. Unknown parameters from any source are ignored; by default they emit warnings, which can be suppressed by requesting the message with `-ReturnUnknownParams` or by using `-NoWarn`. + ## Wrapper action usage ```yaml diff --git a/docs/action-call-reference.md b/docs/action-call-reference.md index a403dfc2..ba47abde 100644 --- a/docs/action-call-reference.md +++ b/docs/action-call-reference.md @@ -111,7 +111,7 @@ See [missing-in-project](actions/missing-in-project.md) for all parameters. - uses: LabVIEW-Community-CI-CD/open-source-actions/missing-in-project@v1 with: lv_version: '2020' - arch: '64' + supported_bitness: '64' project_file: 'MyProject.lvproj' ``` diff --git a/docs/actions/missing-in-project.md b/docs/actions/missing-in-project.md index 0176b083..9263a35d 100644 --- a/docs/actions/missing-in-project.md +++ b/docs/actions/missing-in-project.md @@ -11,7 +11,7 @@ Common parameters are described in [Common parameters](../common-parameters.md). ### Required - **LVVersion** (`string`): LabVIEW version used to open the project. -- **Arch** (`string`): "32" or "64" bitness of LabVIEW. +- **SupportedBitness** (`string`): "32" or "64" bitness of LabVIEW. - **ProjectFile** (`string`): Path to the project file to inspect. ### Optional @@ -23,7 +23,7 @@ None. ```powershell pwsh -File actions/Invoke-OSAction.ps1 -ActionName missing-in-project -ArgsJson '{ "LVVersion": "2020", - "Arch": "64", + "SupportedBitness": "64", "ProjectFile": "MyProject.lvproj" }' ``` @@ -35,7 +35,7 @@ GitHub Action inputs are provided in `snake_case`, while CLI parameters use `Pas | Input | CLI parameter | Description | | --- | --- | --- | | `lv_version` | `LVVersion` | LabVIEW version to use. | -| `arch` | `Arch` | Target architecture (32 or 64). | +| `supported_bitness` | `SupportedBitness` | Target LabVIEW bitness (32 or 64). | | `project_file` | `ProjectFile` | Path to the LabVIEW project (.lvproj). | | `gcli_path` | `gcliPath` | Optional path to the g-cli executable. | | `working_directory` | `WorkingDirectory` | Base directory for the action; relative paths are resolved from here. | @@ -49,7 +49,7 @@ GitHub Action inputs are provided in `snake_case`, while CLI parameters use `Pas uses: LabVIEW-Community-CI-CD/open-source-actions/missing-in-project@v1 with: lv_version: '2020' - arch: '64' + supported_bitness: '64' project_file: 'MyProject.lvproj' ``` diff --git a/docs/adapter-authoring.md b/docs/adapter-authoring.md index 9db0f445..17c82aa7 100644 --- a/docs/adapter-authoring.md +++ b/docs/adapter-authoring.md @@ -59,7 +59,7 @@ function Invoke-MyNewAction { After adding your adapter function, regenerate the dispatcher registry: -1. Run `npm run derive:registry` to update `dispatchers.json`. +1. Run `npx tsx scripts/derive-dispatcher-registry.ts` to update `dispatchers.json`. 2. Commit the regenerated file. ## Logging and Verbosity diff --git a/docs/common-parameters.md b/docs/common-parameters.md index 5cbac203..6f3ca973 100644 --- a/docs/common-parameters.md +++ b/docs/common-parameters.md @@ -24,6 +24,16 @@ Example: pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsJson '{}' -DryRun ``` +### `-FailOnUnknown` + +Treats unsupported parameters as errors. By default, the dispatcher ignores unknown parameters and emits a warning. Specify `-FailOnUnknown` to throw instead. + +Example: + +```powershell +pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsJson '{}' -FailOnUnknown +``` + ### `-WorkingDirectory` Runs the adapter after changing to the specified directory using `-WorkingDirectory`. diff --git a/docs/environment-setup.md b/docs/environment-setup.md new file mode 100644 index 00000000..5914cfd4 --- /dev/null +++ b/docs/environment-setup.md @@ -0,0 +1,49 @@ +# Environment Setup + +This guide lists the tooling required to contribute to Open Source LabVIEW Actions and how to verify each component. + +## PowerShell 7.5.1 + +PowerShell 7.5.1 or newer is required. Verify the version: + +```bash +pwsh --version +``` + +## Node.js 24+ + +Install Node.js 24 or newer. Verify the installation: + +```bash +node --version +``` + +## actionlint + +[actionlint](https://github.com/rhysd/actionlint) validates GitHub Actions workflows. +Install it with Go and confirm it is on `PATH`: + +```bash +go install github.com/rhysd/actionlint/cmd/actionlint@latest +actionlint -version +``` + +## g-cli + +Some actions rely on NI's LabVIEW command-line interface (g-cli). +On Windows the executable typically resides at `C:\Program Files\G-CLI\bin\g-cli.exe`. +Verify availability with: + +```powershell +& 'C:\Program Files\G-CLI\bin\g-cli.exe' --version +# or if on PATH +g-cli --version +``` + +## Optional: LABVIEW_ICON_EDITOR_PATH + +Set `LABVIEW_ICON_EDITOR_PATH` if a nonstandard icon editor is required. Check the value with: + +```powershell +echo $env:LABVIEW_ICON_EDITOR_PATH +``` diff --git a/docs/index.md b/docs/index.md index a0173424..e3b2466d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,6 +6,7 @@ Open Source LabVIEW Actions unifies LabVIEW CI/CD scripts behind a single PowerS - [Architecture](architecture.md) - [Quickstart](quickstart.md) +- [Environment Setup](environment-setup.md) - [Action Call Reference](action-call-reference.md) - [Common Parameters](common-parameters.md) - [Adapter Authoring Guide](adapter-authoring.md) diff --git a/docs/quickstart.md b/docs/quickstart.md index 69598f0b..449dc150 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,6 +1,6 @@ # Quickstart -1. **Install Requirements:** Ensure you have **NI LabVIEW** (with command-line interface support, often via *g-cli*) installed on the target runner. Most actions require LabVIEW and the NI g-cli tool to be available (Ubuntu runners are recommended). Also verify PowerShell 7+ (`pwsh`) is available for cross-platform script execution. Install **Node.js 24+** and run `npm install` to pull in the TypeScript dependencies used by helper scripts. +1. **Install Requirements:** Ensure you have **NI LabVIEW** (with command-line interface support, often via *g-cli*) installed on the target runner. Most actions require LabVIEW and the NI g-cli tool to be available (Ubuntu runners are recommended). Also verify PowerShell 7+ (`pwsh`) is available for cross-platform script execution. Install **Node.js 24+** and run `npm install` to pull in the TypeScript dependencies used by helper scripts. Decide whether to execute on a standard GitHub-hosted runner or an integration runner with preinstalled tooling; see [runner-types](runner-types.md) for details. 2. **Invoke via Composite Action (GitHub):** Use the adapter-specific action in your workflow. For example, to **build a LabVIEW Packed Library**: ```yaml diff --git a/docs/relative-paths.md b/docs/relative-paths.md new file mode 100644 index 00000000..4f0b3c29 --- /dev/null +++ b/docs/relative-paths.md @@ -0,0 +1,8 @@ +# Relative Path Normalization + +Dispatcher actions accept a `RelativePath` argument that points to the project root relative to the working directory. Before invoking adapter functions, the dispatcher normalizes this value: + +- trailing directory separators are removed +- `.` segments are resolved + +Inputs such as `./` or `scripts/../` therefore become `.` and `scripts`. Normalization ensures all scripts receive consistent paths regardless of how callers format the argument. diff --git a/docs/requirements.md b/docs/requirements.md index 7e2d2531..21498d18 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -2,11 +2,13 @@ This project tracks high‑level requirements and maps each one to the Pester test files that verify it. The authoritative mapping is stored in [`requirements.json`](../requirements.json); the table below provides a human‑readable summary for quick reference. +Runner Type indicates whether a requirement runs on a standard GitHub-hosted image or an integration runner with preinstalled tooling. See [runner-types](runner-types.md) for guidance on choosing between them. + | ID | Description | Tests | Runner | Runner Type | Skip Dry Run | |----|-------------|-------|--------|-------------|--------------| | REQ-001 | Dispatcher discovers available actions, describes them, and validates arguments. | `tests/pester/Dispatcher.Tests.ps1` | | | | | REQ-002 | Dispatcher dry-run mode prints descriptions and warns on unknown arguments without executing actions. | `tests/pester/Dispatcher.DryRun.Tests.ps1` | | | | -| REQ-003 | Actions resolve RelativePath arguments using the action's WorkingDirectory as the base path and pass them without warnings, including when RelativePath is '.' and the WorkingDirectory targets subdirectories. | `tests/pester/RelativePath.Actions.Tests.ps1` | | | | +| REQ-003 | Actions resolve and normalize RelativePath arguments (trimming separators, resolving '.') using the action's WorkingDirectory as the base path and pass them without warnings, including when RelativePath is '.' and the WorkingDirectory targets subdirectories. | `tests/pester/RelativePath.Actions.Tests.ps1` | | | | | REQ-004 | Every action script exists at the expected path. | `tests/pester/ScriptPath.Tests.ps1` | | | | | REQ-005 | Dispatcher fails when RelativePath is missing or invalid after resolving it relative to the specified WorkingDirectory. | `tests/pester/Dispatcher.InvalidPaths.Tests.ps1` | | | | | REQ-006 | Workflow tests the composite action defined in apply-vipc/action.yml with minimum_supported_lv_version '2021', vip_lv_version '2021', supported_bitness '64', relative_path '.', and vipc_path 'scripts/apply-vipc/runner_dependencies.vipc' on the GitHub-hosted Ubuntu runner labeled ubuntu-latest with dry_run true. | `tests/pester/ApplyVipc.DryRunTrue.Workflow.ps1` | ubuntu-latest | integration | false | diff --git a/docs/runner-types.md b/docs/runner-types.md new file mode 100644 index 00000000..b41c7a73 --- /dev/null +++ b/docs/runner-types.md @@ -0,0 +1,55 @@ +# Runner Types: Integration vs Default + +Modern CI pipelines in this repository classify runners into two categories to control cost and coverage. Understanding the difference allows you to target expensive resources only when necessary and keep feedback cycles fast. + +## Default ("standard") runners + +* **Environment** – GitHub-hosted virtual machines such as `ubuntu-latest` or `windows-latest`. +* **Use cases** – Linting, unit tests and any step that can run on a clean ephemeral image. +* **Configuration** – In `requirements.json` omit `runner_type` or set it to `standard`. Workflows simply use `runs-on: ubuntu-latest` or similar. +* **Characteristics** – High concurrency, minimal boot time and no persistent state. Ideal for rapid validation. + +## Integration runners + +* **Environment** – Long-lived machines with preinstalled tooling such as LabVIEW, g-cli and hardware drivers. They may be self-hosted or specialized GitHub images. +* **Use cases** – End‑to‑end scenarios that interact with external systems, require licensed software or need deterministic state. +* **Configuration** – Tag the runner with `runner_type: "integration"` in `requirements.json` and reference the runner by label in workflows. Integration entries often set `skip_dry_run: true` to force real execution. +* **Characteristics** – Limited availability and higher cost; jobs are serialized to protect shared resources. Treat these runners as scarce infrastructure. + +## Declaring runner types + +The `requirements.json` file defines which runner each test or requirement targets: + +```json +{ + "runners": { + "ubuntu-latest": { + "runner_label": "ubuntu-latest", + "runner_type": "integration" + }, + "windows-latest": { + "runner_label": "windows-latest" + /* implicit runner_type: "standard" */ + } + }, + "requirements": [ + { + "id": "REQ-009", + "runner": "ubuntu-latest", + "tests": ["Build.Workflow"] + } + ] +} +``` + +The summarizer partitions results by `runner_type`, producing artifacts such as `summary-integration.md` alongside `summary-standard.md`. This separation keeps integration evidence distinct from fast feedback produced on default runners. + +## Recommendations for CI/CD engineers + +1. **Minimize integration usage.** Start with standard runners and move tests to integration environments only when they require external dependencies or state. +2. **Isolate heavy workflows.** Place integration jobs in separate stages or repositories to avoid blocking quick validation paths. +3. **Protect self-hosted runners.** Apply concurrency limits and explicit `needs` chains so multiple integration jobs do not compete for the same hardware. +4. **Audit runner labels.** Keep `requirements.json` synchronized with the actual fleet of self-hosted machines. Stale labels lead to idle jobs. +5. **Document expectations.** When adding new requirements or workflows, update `docs/requirements.md` so the `Runner` and `Runner Type` columns reflect the intended infrastructure. + +By explicitly classifying jobs, teams can scale the project efficiently—routine tasks remain fast on default runners while integration tests validate real‑world behavior without overloading scarce resources. diff --git a/missing-in-project/action.yml b/missing-in-project/action.yml index 894ef66a..4c9c8744 100644 --- a/missing-in-project/action.yml +++ b/missing-in-project/action.yml @@ -4,8 +4,8 @@ inputs: lv_version: description: 'LabVIEW version to use.' required: true - arch: - description: 'Target architecture (32 or 64).' + supported_bitness: + description: 'Target LabVIEW bitness (32 or 64).' required: true project_file: description: 'Path to the LabVIEW project (.lvproj).' @@ -33,7 +33,7 @@ runs: $ErrorActionPreference = 'Stop' $args = @{ LVVersion = '${{ inputs.lv_version }}' - Arch = '${{ inputs.arch }}' + SupportedBitness = '${{ inputs.supported_bitness }}' ProjectFile = '${{ inputs.project_file }}' } if ('${{ inputs.gcli_path }}') { $args['gcliPath'] = '${{ inputs.gcli_path }}' } diff --git a/requirements.json b/requirements.json index 92e04c9a..2842df3e 100644 --- a/requirements.json +++ b/requirements.json @@ -1,19 +1,19 @@ { "runners": { - "windows-latest": { - "owner": "windows-latest", - "runner_label": "windows-latest", + "self-hosted-windows-lv-integration": { + "owner": "NI", + "runner_label": "self-hosted-windows-lv", "runner_type": "integration", "skip_dry_run": false }, - "self-hosted-windows-lv": { - "owner": "self-hosted-windows-lv", + "self-hosted-windows-lv-default": { + "owner": "NI", "runner_label": "self-hosted-windows-lv", - "runner_type": "integration", + "runner_type": "default", "skip_dry_run": false }, "ubuntu-latest": { - "owner": "ubuntu-latest", + "owner": "GitHub Actions", "runner_label": "ubuntu-latest", "runner_type": "integration", "skip_dry_run": false @@ -264,7 +264,7 @@ "id": "REQIE-001", "description": "After checking out the LabVIEW icon editor repository, PreSequence: The sequencer shall enumerate and record the build matrix used by the workflow (LabVIEW versions and bitness). Acceptance: a 'matrix.json' file exists listing each tuple {\"lv-version\": \"2021\"|\"2023\", \"bitness\": \"32\"|\"64\"} with at least [ [\"2021\",\"32\"], [\"2021\",\"64\"], [\"2023\",\"64\"] ]. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.PreSequence.matrix-enumeration" ] @@ -273,7 +273,7 @@ "id": "REQIE-002", "description": "After checking out the LabVIEW icon editor repository, Setup: For each matrix entry, the sequencer shall apply VIPC dependencies using the canonical action inputs (minimum_supported_lv_version, vip_lv_version, supported_bitness, relative_path). Evidence: a 'vipc-apply.json' summary per matrix entry capturing inputs, start/end timestamps, exit code, and status. Acceptance: all entries report exit_code == 0 and status == 'success'. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Setup.apply-vipc-succeeds" ] @@ -282,7 +282,7 @@ "id": "REQIE-003", "description": "After checking out the LabVIEW icon editor repository, Setup: The sequencer shall compute and persist semantic version information. Evidence: a 'version.json' containing VERSION, MAJOR, MINOR, PATCH, BUILD, IS_PRERELEASE and the commit SHA used. Acceptance: VERSION conforms to SemVer and all numeric components are present. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Setup.version-outputs-captured" ] @@ -291,7 +291,7 @@ "id": "REQIE-004", "description": "After checking out the LabVIEW icon editor repository, Setup: The 'missing-in-project' check shall be executed for the specified LabVIEW version(s) and both 32-bit and 64-bit bitness as applicable. Evidence: 'missing-in-project.json' including project-file, lv-version, bitness, and result. Acceptance: result == 'present' for expected module paths. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Setup.missing-in-project-matrix" ] @@ -300,7 +300,7 @@ "id": "REQIE-005", "description": "After checking out the LabVIEW icon editor repository, Main: Unit tests shall be executed (Pester) across the configured matrix. Evidence: a 'pester-summary.json' file containing total, passed, failed, skipped, duration_ms, and per-test results; XML output is not required. Acceptance: failed == 0 and total >= 1. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Main.unit-tests-pass" ] @@ -309,7 +309,7 @@ "id": "REQIE-006", "description": "After checking out the LabVIEW icon editor repository, Main: Build Packed Libraries (PPL) shall succeed for both 32-bit and 64-bit targets. Evidence: existence of 'resource/plugins/lv_icon_x86.lvlibp' and 'resource/plugins/lv_icon_x64.lvlibp' and a 'ppl.hash' file containing SHA256 for each artifact. Acceptance: non-zero artifact sizes and matching SHA256 re-computation. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Main.ppl-built-and-hashed", "BuildProfile1.IconEditor.Main.artifact-size-nonzero" @@ -319,7 +319,7 @@ "id": "REQIE-007", "description": "After checking out the LabVIEW icon editor repository, Main: Renaming and artifact upload steps shall complete. Evidence: an 'artifact-manifest.json' listing uploaded artifact names ('lv_icon_x86.lvlibp', 'lv_icon_x64.lvlibp'), paths, and sizes. Acceptance: manifest entries match on-disk files and GitHub Artifacts report success. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Main.artifacts-renamed-and-uploaded" ] @@ -328,7 +328,7 @@ "id": "REQIE-008", "description": "After checking out the LabVIEW icon editor repository, Main: The workflow shall generate a VI Package (.vip) using the prescribed actions and inputs. Evidence: 'vi-package.hash' (SHA256 of produced .vip), and a 'vi-package.json' summarizing package metadata (name, version, company, build). Acceptance: at least one .vip exists, size > 0, and hash is recorded. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Main.vi-package-built-and-hashed" ] @@ -337,7 +337,7 @@ "id": "REQIE-009", "description": "After checking out the LabVIEW icon editor repository, Main: The workflow shall produce a display information JSON for the VI Package and inject it prior to packaging. Evidence: 'display-info.json' containing the exact keys used by the action (Package Version.major/minor/patch/build, Product/Company/Author fields, etc.). Acceptance: all required keys exist and reflect the computed version (REQ-011). g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Main.display-info-generated" ] @@ -346,7 +346,7 @@ "id": "REQIE-010", "description": "After checking out the LabVIEW icon editor repository, Cleanup: The workflow shall terminate any LabVIEW processes via the 'close-labview' step for each applicable bitness. Evidence: 'close-labview.log' including bitness, attempts, and final process list. Acceptance: no LabVIEW process remains after the step. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.Cleanup.labview-closed" ] @@ -355,7 +355,7 @@ "id": "REQIE-011", "description": "After checking out the LabVIEW icon editor repository, PostSequence: The sequencer shall assemble a canonical single-line CI evidence string summarizing statuses and key facts for REQ-001..REQ-018. The string SHALL be a minified JSON assigned to a step output named 'CI_EVIDENCE' and saved as 'ci_evidence.txt'. Acceptance: the string parses as JSON and includes {\"pipeline\":\"IconEditor\", \"git_sha\":..., \"matrix\":[...], \"version\":{...}, \"artifacts\":{...}, \"req_status\":{\"REQ-001\":\"PASS\"|\"FAIL\", ...}}. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.PostSequence.ci-evidence-assembled", "BuildProfile1.IconEditor.PostSequence.ci-evidence-output" @@ -365,10 +365,10 @@ "id": "REQIE-012", "description": "After checking out the LabVIEW icon editor repository, PostSequence: The CI evidence string shall be logged succinctly to the job summary and made available to downstream jobs via $GITHUB_OUTPUT. Evidence: the step output 'CI_EVIDENCE' is present and a 'summary.md' contains a redacted preview. Acceptance: dependent jobs can read 'needs..outputs.CI_EVIDENCE' and parse it successfully. g-cli is expected at 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe'.", "skip_dry_run": true, - "runner": "self-hosted-windows-lv", + "runner": "self-hosted-windows-lv-integration", "tests": [ "BuildProfile1.IconEditor.PostSequence.ci-evidence-published" ] } ] -} \ No newline at end of file +} diff --git a/scripts/__tests__/generate-ci-summary.test.js b/scripts/__tests__/generate-ci-summary.test.js index 35dc8c53..1d50a1a2 100644 --- a/scripts/__tests__/generate-ci-summary.test.js +++ b/scripts/__tests__/generate-ci-summary.test.js @@ -155,7 +155,7 @@ test('writes outputs to OS-specific directory', async () => { const env = { ...process.env, - TEST_RESULTS_GLOB: junitPath, + TEST_RESULTS_GLOBS: junitPath, EVIDENCE_DIR: tmp, RUNNER_OS: 'Windows', }; @@ -196,7 +196,7 @@ test('partitions requirement groups by runner_type', async () => { const env = { ...process.env, - TEST_RESULTS_GLOB: junitPath, + TEST_RESULTS_GLOBS: junitPath, EVIDENCE_DIR: dir, REQ_MAPPING_FILE: reqPath, RUNNER_OS: 'Linux', diff --git a/scripts/build/Build.ps1 b/scripts/build/Build.ps1 index c214a313..12b5482c 100644 --- a/scripts/build/Build.ps1 +++ b/scripts/build/Build.ps1 @@ -82,15 +82,14 @@ function Execute-Script { Invoke-Expression $command Write-Verbose "Command completed. Checking exit code..." if ($LASTEXITCODE -ne 0) { - Write-Host "Error occurred while executing: `"$ScriptPath`" with arguments: `"$Arguments`". Exit code: $LASTEXITCODE" -ForegroundColor Red - exit $LASTEXITCODE + Write-Error "Error occurred while executing: `"$ScriptPath`" with arguments: `"$Arguments`". Exit code: $LASTEXITCODE" + throw "Script failed with exit code $LASTEXITCODE" } Write-Verbose "Exit code is 0; no errors detected." } catch { - Write-Host "Error occurred while executing: `"$ScriptPath`" with arguments: `"$Arguments`". Exiting." -ForegroundColor Red - Write-Verbose "Exception details: $($_.Exception.Message)" - exit 1 + Write-Error "Error occurred while executing: `"$ScriptPath`" with arguments: `"$Arguments`"" + throw } } @@ -266,7 +265,7 @@ try { Write-Verbose "Script: Build.ps1 completed without errors." } catch { - Write-Host "An unexpected error occurred during script execution: $($_.Exception.Message)" -ForegroundColor Red + Write-Error "An unexpected error occurred during script execution: $($_.Exception.Message)" Write-Verbose "Stack Trace: $($_.Exception.StackTrace)" exit 1 } diff --git a/scripts/build/README.md b/scripts/build/README.md index 77fc1fe3..fcb1c10c 100644 --- a/scripts/build/README.md +++ b/scripts/build/README.md @@ -33,6 +33,10 @@ Runs **`Build.ps1`** to clean, compile, and package the LabVIEW Icon Editor. See also: [docs/actions/build.md](../../docs/actions/build.md) +## Error handling + +On failure the script outputs `An unexpected error occurred during script execution:
` and returns a non-zero exit code. + ## License This directory inherits the root repository’s license (MIT, unless otherwise noted). diff --git a/scripts/derive-dispatcher-registry.ts b/scripts/derive-dispatcher-registry.ts index 495a0e06..cf882c46 100644 --- a/scripts/derive-dispatcher-registry.ts +++ b/scripts/derive-dispatcher-registry.ts @@ -15,6 +15,17 @@ interface FuncInfo { parameters: Record; } +function attachParamDescriptions(info: FuncInfo) { + if (!info.description) return; + for (const [name, param] of Object.entries(info.parameters)) { + const regex = new RegExp(`\\b${name}:\\s*([^\\.]+)`, 'i'); + const match = info.description.match(regex); + if (match) { + param.description = match[1].trim(); + } + } +} + function parseParams(block: string): Record { const params: Record = {}; const lines = block.split(/\r?\n/).map(l => l.trim()).filter(Boolean); @@ -94,7 +105,7 @@ async function main() { const registry: Record = {}; for (const file of files) { const content = await fs.readFile(file, 'utf8'); - const fnRegex = /function\s+(\w+)\b/gi; + const fnRegex = /function\s+([\w-]+)\b/gi; let match: RegExpExecArray | null; while ((match = fnRegex.exec(content)) !== null) { const fn = match[1]; @@ -104,8 +115,10 @@ async function main() { if (!paramsBlock) continue; const description = extractDescription(content, match.index); registry[fn] = { description, parameters: parseParams(paramsBlock) }; + attachParamDescriptions(registry[fn]); } } + delete registry['Invoke-OpenSourceActionScript']; for (const info of Object.values(registry)) { if (info.parameters.RelativePath) { info.parameters.RelativePath.description = diff --git a/scripts/dummy.test.js b/scripts/dummy.test.js deleted file mode 100644 index 03adc735..00000000 --- a/scripts/dummy.test.js +++ /dev/null @@ -1,3 +0,0 @@ -import test from 'node:test'; - -test('dummy', () => {}); diff --git a/scripts/missing-in-project/Invoke-MissingInProjectCLI.ps1 b/scripts/missing-in-project/Invoke-MissingInProjectCLI.ps1 index 454714f3..865c0595 100644 --- a/scripts/missing-in-project/Invoke-MissingInProjectCLI.ps1 +++ b/scripts/missing-in-project/Invoke-MissingInProjectCLI.ps1 @@ -2,7 +2,7 @@ [CmdletBinding()] param( [Parameter(Mandatory)][string]$LVVersion, - [Parameter(Mandatory)][ValidateSet('32','64')][string]$Arch, + [Parameter(Mandatory)][ValidateSet('32','64')][string]$SupportedBitness, [Parameter(Mandatory)][string]$ProjectFile ) @@ -24,9 +24,9 @@ if (-not (Test-Path $HelperPath)) { # ========================= SETUP ========================= function Setup { Write-Host "=== Setup ===" - Write-Host "LVVersion : $LVVersion" - Write-Host "Arch : $Arch-bit" - Write-Host "ProjectFile: $ProjectFile" + Write-Host "LVVersion : $LVVersion" + Write-Host "SupportedBitness: $SupportedBitness-bit" + Write-Host "ProjectFile : $ProjectFile" # remove an old results file to avoid stale data if (Test-Path $MissingFilePath) { @@ -42,11 +42,11 @@ function MainSequence { Write-Host "Invoking missing‑file check via helper script …`n" # call helper & capture any stdout (not strictly needed now) - & $HelperPath -LVVersion $LVVersion -Arch $Arch -ProjectFile $ProjectFile + & $HelperPath -LVVersion $LVVersion -SupportedBitness $SupportedBitness -ProjectFile $ProjectFile $Script:HelperExitCode = $LASTEXITCODE # Ensure LabVIEW is closed (redundant if helper did it) - & g-cli --lv-ver $LVVersion --arch $Arch QuitLabVIEW | Out-Null + & g-cli --lv-ver $LVVersion --arch $SupportedBitness QuitLabVIEW | Out-Null if ($Script:HelperExitCode -ne 0) { Write-Error "Helper returned non‑zero exit code: $Script:HelperExitCode" diff --git a/scripts/missing-in-project/README.md b/scripts/missing-in-project/README.md index 82fcc7ae..8f0867a6 100644 --- a/scripts/missing-in-project/README.md +++ b/scripts/missing-in-project/README.md @@ -39,7 +39,7 @@ Results are returned as standard GitHub Action outputs so downstream jobs can d | Name | Required | Example | Description | |------|----------|---------|-------------| | `lv-ver` | **Yes** | `2021` | LabVIEW _major_ version number that should be used to run `MissingInProjectCLI.vi` | -| `arch` | **Yes** | `32` or `64` | Bitness of the LabVIEW runtime to launch | +| `supported-bitness` | **Yes** | `32` or `64` | Bitness of the LabVIEW runtime to launch | | `project-file` | No | `source/MyPlugin.lvproj` | Path (absolute or relative to repository root) of the project to inspect. Defaults to **`lv_icon.lvproj`** | --- @@ -70,7 +70,7 @@ jobs: uses: ./.github/actions/missing-in-project with: lv-ver: 2021 - arch: 64 + supported-bitness: 64 - name: Print report if: ${{ steps.mip.outputs.passed == 'false' }} @@ -90,13 +90,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - arch: [32, 64] + supported_bitness: [32, 64] steps: - uses: actions/checkout@v4 - uses: ./.github/actions/missing-in-project with: lv-ver: 2021 - arch: ${{ matrix.arch }} + supported-bitness: ${{ matrix.supported_bitness }} build-package: needs: missing-in-project-check @@ -143,7 +143,7 @@ jobs: ```powershell pwsh -File .github/actions/missing-in-project/Invoke-MissingInProjectCLI.ps1 ` -LVVersion 2021 ` - -Arch 64 ` + -SupportedBitness 64 ` -ProjectFile 'C:\path\to\MyProj.lvproj' echo "Exit code: $LASTEXITCODE" diff --git a/scripts/missing-in-project/RunMissingCheckWithGCLI.ps1 b/scripts/missing-in-project/RunMissingCheckWithGCLI.ps1 index fe5032fa..ff83b18e 100644 --- a/scripts/missing-in-project/RunMissingCheckWithGCLI.ps1 +++ b/scripts/missing-in-project/RunMissingCheckWithGCLI.ps1 @@ -5,7 +5,7 @@ .PARAMETER LVVersion LabVIEW version (e.g. "2021"). -.PARAMETER Arch +.PARAMETER SupportedBitness Bitness ("32" or "64"). .PARAMETER ProjectFile @@ -19,7 +19,7 @@ [CmdletBinding()] param( [Parameter(Mandatory)][string]$LVVersion, - [Parameter(Mandatory)][ValidateSet('32','64')][string]$Arch, + [Parameter(Mandatory)][ValidateSet('32','64')][string]$SupportedBitness, [Parameter(Mandatory)][string]$ProjectFile ) $ErrorActionPreference = 'Stop' @@ -46,13 +46,13 @@ if (-not (Test-Path $ProjectFile)) { Write-Host "ℹ️ VI path : $viPath" Write-Host "ℹ️ Project file : $ProjectFile" -Write-Host "ℹ️ LabVIEW ver : $LVVersion ($Arch-bit)" +Write-Host "ℹ️ LabVIEW ver : $LVVersion ($SupportedBitness-bit)" Write-Host "--------------------------------------------------" # ---------- build argument list & invoke ---------- $gcliArgs = @( '--lv-ver', $LVVersion, - '--arch', $Arch, + '--arch', $SupportedBitness, $viPath, '--', $ProjectFile @@ -71,7 +71,7 @@ if ($exitCode -eq 0) { } # close LabVIEW if still running (harmless if not) -& g-cli --lv-ver $LVVersion --arch $Arch QuitLabVIEW | Out-Null +& g-cli --lv-ver $LVVersion --arch $SupportedBitness QuitLabVIEW | Out-Null $global:LASTEXITCODE = $exitCode return diff --git a/scripts/revert-development-mode/README.md b/scripts/revert-development-mode/README.md index 30afed6f..fecd5dcb 100644 --- a/scripts/revert-development-mode/README.md +++ b/scripts/revert-development-mode/README.md @@ -18,6 +18,10 @@ Invoke **`RevertDevelopmentMode.ps1`** to restore packaged sources after develop See also: [docs/actions/revert-development-mode.md](../../docs/actions/revert-development-mode.md) +## Error handling + +Failures emit `An unexpected error occurred during script execution:
` and the script exits with a non-zero status. + ## License This directory inherits the root repository’s license (MIT, unless otherwise noted). diff --git a/scripts/revert-development-mode/RevertDevelopmentMode.ps1 b/scripts/revert-development-mode/RevertDevelopmentMode.ps1 index c8c3b630..0f7589fb 100644 --- a/scripts/revert-development-mode/RevertDevelopmentMode.ps1 +++ b/scripts/revert-development-mode/RevertDevelopmentMode.ps1 @@ -41,7 +41,7 @@ function Execute-Script { throw "Script failed with exit code $LASTEXITCODE" } } catch { - Write-Error "Error occurred while executing: $ScriptCommand. $_" + Write-Error "Error occurred while executing: $ScriptCommand" if (-not $LASTEXITCODE) { $global:LASTEXITCODE = 1 } diff --git a/scripts/set-development-mode/README.md b/scripts/set-development-mode/README.md index d5f2c1bb..9a9a8654 100644 --- a/scripts/set-development-mode/README.md +++ b/scripts/set-development-mode/README.md @@ -18,6 +18,10 @@ Execute **`Set_Development_Mode.ps1`** to prepare the repository for active deve See also: [docs/actions/set-development-mode.md](../../docs/actions/set-development-mode.md) +## Error handling + +Failures produce the message `An unexpected error occurred during script execution:
` and the script exits with a non-zero status. + ## License This directory inherits the root repository’s license (MIT, unless otherwise noted). diff --git a/scripts/set-development-mode/Set_Development_Mode.ps1 b/scripts/set-development-mode/Set_Development_Mode.ps1 index 34d5cf58..23604c93 100644 --- a/scripts/set-development-mode/Set_Development_Mode.ps1 +++ b/scripts/set-development-mode/Set_Development_Mode.ps1 @@ -27,7 +27,8 @@ function Execute-Script { try { Invoke-Expression $ScriptCommand -ErrorAction Stop } catch { - throw "Error occurred while executing: $ScriptCommand" + Write-Error "Error occurred while executing: $ScriptCommand" + throw } } # Sequential script execution with error handling diff --git a/tests/pester/Dispatcher.ArgsInputs.Tests.ps1 b/tests/pester/Dispatcher.ArgsInputs.Tests.ps1 index 6257bb56..c68c7172 100644 --- a/tests/pester/Dispatcher.ArgsInputs.Tests.ps1 +++ b/tests/pester/Dispatcher.ArgsInputs.Tests.ps1 @@ -1,3 +1,14 @@ +#requires -Version 7.0 +# Pester tests verifying dispatcher argument inputs and precedence. +# Requirement: REQ-000 - Dispatcher merges argument sources and warns on unknown parameters. + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..' '..')).Path +$global:dispatcher = Join-Path $repoRoot 'actions' 'Invoke-OSAction.ps1' +Import-Module (Join-Path $PSScriptRoot 'Helper' 'ArgsJson.psm1') + Describe 'Dispatcher Args Inputs' { $meta = @{ requirement = 'REQ-000' @@ -5,7 +16,55 @@ Describe 'Dispatcher Args Inputs' { Evidence = 'tests/pester/Dispatcher.ArgsInputs.Tests.ps1' } - It 'dummy test' -Tag 'REQ-000' { - $true | Should -BeTrue + It 'accepts ArgsJson and warns on unknown parameters' -Tag 'REQ-000' { + $params = Get-LabVIEWIconEditorArgsJson + $projectRoot = $params.WorkingDirectory + + $json = @{ + MinimumSupportedLVVersion = '2021' + SupportedBitness = '64' + Extra = 'value' + } | ConvertTo-Json -Compress + + $out = & $global:dispatcher -ActionName close-labview -ArgsJson $json -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String + $LASTEXITCODE | Should -Be 0 + $out | Should -Match '"SupportedBitness":"64"' + $out | Should -Match "Ignored unknown parameters for 'close-labview': Extra" + } + + It 'accepts ArgsFile and warns on unknown parameters' -Tag 'REQ-000' { + $params = Get-LabVIEWIconEditorArgsJson + $projectRoot = $params.WorkingDirectory + + $jsonFile = Join-Path $TestDrive 'args.json' + @{ MinimumSupportedLVVersion = '2021'; SupportedBitness = '64'; Extra = 'value' } | + ConvertTo-Json -Compress | Set-Content -Path $jsonFile + + $out = & $global:dispatcher -ActionName close-labview -ArgsFile $jsonFile -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String + $LASTEXITCODE | Should -Be 0 + $out | Should -Match '"SupportedBitness":"64"' + $out | Should -Match "Ignored unknown parameters for 'close-labview': Extra" + } + + It 'uses inline args to override file and warns on all unknown parameters' -Tag 'REQ-000' { + $params = Get-LabVIEWIconEditorArgsJson + $projectRoot = $params.WorkingDirectory + + $file = Join-Path $TestDrive 'args.json' + @{ MinimumSupportedLVVersion = '2021'; SupportedBitness = '32'; FileExtra = 1 } | + ConvertTo-Json -Compress | Set-Content -Path $file + + $json = @{ SupportedBitness = '64'; JsonExtra = 2 } | ConvertTo-Json -Compress + $table = @{ MinimumSupportedLVVersion = '2019'; TableExtra = 3 } + + $out = & $global:dispatcher -ActionName close-labview -ArgsFile $file -ArgsJson $json -ArgsHashtable $table -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String + $LASTEXITCODE | Should -Be 0 + $out | Should -Match '"MinimumSupportedLVVersion":"2019"' + $out | Should -Match '"SupportedBitness":"64"' + $out | Should -Match 'Ignored unknown parameters' + $out | Should -Match 'FileExtra' + $out | Should -Match 'JsonExtra' + $out | Should -Match 'TableExtra' } } + diff --git a/tests/pester/Dispatcher.DryRun.Tests.ps1 b/tests/pester/Dispatcher.DryRun.Tests.ps1 index 803084c2..a9ed5bd5 100644 --- a/tests/pester/Dispatcher.DryRun.Tests.ps1 +++ b/tests/pester/Dispatcher.DryRun.Tests.ps1 @@ -31,7 +31,6 @@ Describe 'Unified Dispatcher — DryRun behavior for all actions' { LabVIEWMinorRevision = '2021' VIPBPath = 'dummy.vipb' LVVersion = '2021' - Arch = '64' ProjectFile = 'Project.lvproj' Major = 1 Minor = 0 @@ -50,14 +49,14 @@ Describe 'Unified Dispatcher — DryRun behavior for all actions' { } foreach ($kvp in $extra.GetEnumerator()) { $script:args | Add-Member -NotePropertyName $kvp.Key -NotePropertyValue $kvp.Value } $script:argsJson = $script:args | ConvertTo-Json -Compress - $actions = pwsh -NoProfile -File $global:dispatcher -ListActions -WorkingDirectory $script:projectRoot | + $actions = & $global:dispatcher -ListActions -WorkingDirectory $script:projectRoot | Where-Object { $_ -match '^\s+- ' } | ForEach-Object { @{ Action = $_.Trim().Substring(2); ArgsJson = $script:argsJson } } It "describes " -Tag 'REQ-002' -ForEach $actions { param($Action, $ArgsJson) Write-Host "Testing $Action with ArgsJson $ArgsJson" - pwsh -NoProfile -File $global:dispatcher -Describe $Action -ArgsJson $ArgsJson -WorkingDirectory $script:projectRoot *> $null + & $global:dispatcher -Describe $Action -ArgsJson $ArgsJson -WorkingDirectory $script:projectRoot *> $null $LASTEXITCODE | Should -Be 0 } diff --git a/tests/pester/Dispatcher.FailOnUnknown.Tests.ps1 b/tests/pester/Dispatcher.FailOnUnknown.Tests.ps1 new file mode 100644 index 00000000..269ea336 --- /dev/null +++ b/tests/pester/Dispatcher.FailOnUnknown.Tests.ps1 @@ -0,0 +1,32 @@ +#requires -Version 7.0 +# Pester tests verifying dispatcher FailOnUnknown switch. +# Requirement: REQ-000 - Dispatcher merges argument sources and warns on unknown parameters. + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..' '..')).Path +$global:dispatcher = Join-Path $repoRoot 'actions' 'Invoke-OSAction.ps1' +Import-Module (Join-Path $PSScriptRoot 'Helper' 'ArgsJson.psm1') + +Describe 'Dispatcher FailOnUnknown' { + $meta = @{ + requirement = 'REQ-000' + Owner = 'DevTools' + Evidence = 'tests/pester/Dispatcher.FailOnUnknown.Tests.ps1' + } + + It 'warns on unknown parameters by default' -Tag 'REQ-000' { + $params = Get-LabVIEWIconEditorArgsJson + $json = @{ MinimumSupportedLVVersion = '2021'; SupportedBitness = '64'; Extra = 'value' } | ConvertTo-Json -Compress + $out = & $global:dispatcher -ActionName close-labview -ArgsJson $json -WorkingDirectory $params.WorkingDirectory -DryRun *>&1 | Out-String + $LASTEXITCODE | Should -Be 0 + $out | Should -Match "Ignored unknown parameters for 'close-labview': Extra" + } + + It 'throws on unknown parameters when FailOnUnknown is set' -Tag 'REQ-000' { + $params = Get-LabVIEWIconEditorArgsJson + $json = @{ MinimumSupportedLVVersion = '2021'; SupportedBitness = '64'; Extra = 'value' } | ConvertTo-Json -Compress + { & $global:dispatcher -ActionName close-labview -ArgsJson $json -WorkingDirectory $params.WorkingDirectory -DryRun -FailOnUnknown } | Should -Throw "Ignored unknown parameters for 'close-labview': Extra" + } +} diff --git a/tests/pester/Dispatcher.InvalidPaths.Tests.ps1 b/tests/pester/Dispatcher.InvalidPaths.Tests.ps1 index 4d1d17d1..1010b75a 100644 --- a/tests/pester/Dispatcher.InvalidPaths.Tests.ps1 +++ b/tests/pester/Dispatcher.InvalidPaths.Tests.ps1 @@ -11,6 +11,7 @@ Import-Module (Join-Path $PSScriptRoot 'Helper' 'ArgsJson.psm1') $params = Get-LabVIEWIconEditorArgsJson $projectRoot = $params.WorkingDirectory +$errorText = 'An unexpected error occurred during script execution' Describe 'Invalid RelativePath handling' { $meta = @{ @@ -23,7 +24,7 @@ Describe 'Invalid RelativePath handling' { $json = @{ RelativePath = 'NoSuchDir' } | ConvertTo-Json -Compress $out = pwsh -NonInteractive -NoProfile -File $global:dispatcher -ActionName set-development-mode -ArgsJson $json -WorkingDirectory $projectRoot *>&1 | Out-String $LASTEXITCODE | Should -Not -Be 0 - $out | Should -Match 'An unexpected error occurred during script execution' + $out | Should -Match $errorText } It 'fails when RelativePath is missing' -Tag 'REQ-005' { diff --git a/tests/pester/Dispatcher.Tests.ps1 b/tests/pester/Dispatcher.Tests.ps1 index 33e05283..b91a630a 100644 --- a/tests/pester/Dispatcher.Tests.ps1 +++ b/tests/pester/Dispatcher.Tests.ps1 @@ -25,7 +25,7 @@ Describe 'Unified Dispatcher — discovery and validation' { $params = Get-LabVIEWIconEditorArgsJson $json = $params.ArgsJson $projectRoot = $params.WorkingDirectory - $out = pwsh -NoProfile -File $global:dispatcher -ListActions -ArgsJson $json -WorkingDirectory $projectRoot | Out-String + $out = & $global:dispatcher -ListActions -ArgsJson $json -WorkingDirectory $projectRoot | Out-String $out | Should -Match 'apply-vipc' $out | Should -Match 'build-lvlibp' $out | Should -Match 'missing-in-project' @@ -34,9 +34,9 @@ Describe 'Unified Dispatcher — discovery and validation' { It 'registry includes all Invoke* adapters in module' -Tag 'REQ-001' { $modulePath = Join-Path (Split-Path $global:dispatcher -Parent) 'OpenSourceActions.psm1' $module = Import-Module $modulePath -PassThru - $fnNames = (Get-Command -Module $module | Where-Object Name -like 'Invoke*').Name + $fnNames = (Get-Command -Module $module | Where-Object { $_.Name -like 'Invoke*' -and $_.Name -ne 'Invoke-OpenSourceActionScript' }).Name function Convert-Name([string]$fn) { - $name = $fn -replace '^Invoke' + $name = $fn -replace '^Invoke-?' $name = $name -creplace '([a-z0-9])([A-Z])', '$1-$2' $name = $name -creplace '([A-Z])([A-Z][a-z])', '$1-$2' $name = $name -ireplace 'Lab-VIEW', 'LabVIEW' @@ -44,7 +44,7 @@ Describe 'Unified Dispatcher — discovery and validation' { } $expected = $fnNames | ForEach-Object { Convert-Name $_ } $wd = (Get-LabVIEWIconEditorArgsJson).WorkingDirectory - $listed = pwsh -NoProfile -File $global:dispatcher -ListActions -WorkingDirectory $wd | Out-String + $listed = & $global:dispatcher -ListActions -WorkingDirectory $wd | Out-String foreach ($action in $expected) { $listed | Should -Match " - $action" } @@ -53,7 +53,7 @@ Describe 'Unified Dispatcher — discovery and validation' { $params = Get-LabVIEWIconEditorArgsJson $json = $params.ArgsJson $projectRoot = $params.WorkingDirectory - $out = pwsh -NoProfile -File $global:dispatcher -Describe build-lvlibp -ArgsJson $json -WorkingDirectory $projectRoot | Out-String + $out = & $global:dispatcher -Describe build-lvlibp -ArgsJson $json -WorkingDirectory $projectRoot | Out-String $out | Should -Match 'Major' $out | Should -Match 'Minor' $out | Should -Match 'Patch' @@ -103,8 +103,12 @@ Describe 'Filter-Args helper' { function Dummy { param([string]$Known) } $args = @{ Known = 'value'; Extra = 'x' } - $result = Filter-Args -InputArgs $args -FuncName 'Dummy' -ActionNameForWarn 'dummy' -ReturnUnknownParams + $warnings = @() + # Capture and suppress warnings to keep test output clean while verifying no warnings are emitted + $result = Filter-Args -InputArgs $args -FuncName 'Dummy' -ActionNameForWarn 'dummy' -ReturnUnknownParams -WarningVariable warnings -WarningAction SilentlyContinue + $warnings | Should -BeNullOrEmpty $result.PSObject.Properties.Name | Should -Contain 'UnknownParams' + $result.UnknownParams | Should -Match 'Extra' } } diff --git a/tests/pester/MissingInProject.Workflow.Tests.ps1 b/tests/pester/MissingInProject.Workflow.Tests.ps1 index 341ba137..5dd1cc21 100644 --- a/tests/pester/MissingInProject.Workflow.Tests.ps1 +++ b/tests/pester/MissingInProject.Workflow.Tests.ps1 @@ -24,7 +24,7 @@ Describe 'MissingInProject.Workflow' { $externalCheckout | Should -BeNullOrEmpty $missingStep.with.lv_version | Should -Be '2021' - $missingStep.with.arch | Should -Be '64' + $missingStep.with.supported_bitness | Should -Be '64' $missingStep.with.project_file | Should -Be 'scripts/missing-in-project/Missing in Project.lvproj' $missingStep.with.relative_path | Should -Be 'scripts/missing-in-project' diff --git a/tests/pester/PathRestoration.Actions.Tests.ps1 b/tests/pester/PathRestoration.Actions.Tests.ps1 index f15b8c11..97462006 100644 --- a/tests/pester/PathRestoration.Actions.Tests.ps1 +++ b/tests/pester/PathRestoration.Actions.Tests.ps1 @@ -28,7 +28,7 @@ Describe 'Adapters restore PATH' -Skip { @{ Func='Invoke-BuildLvlibp'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','build-lvlibp','Build_lvlibp.ps1'); Args=@{ MinimumSupportedLVVersion='2021'; SupportedBitness='64'; RelativePath='.'; LabVIEW_Project='Proj'; Build_Spec='Spec'; Major=1; Minor=0; Patch=0; Build=1; Commit='abc' } }, @{ Func='Invoke-CloseLabVIEW'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','close-labview','Close_LabVIEW.ps1'); Args=@{ MinimumSupportedLVVersion='2021'; SupportedBitness='64' } }, @{ Func='Invoke-GenerateReleaseNotes'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','generate-release-notes','GenerateReleaseNotes.ps1'); Args=@{ OutputPath='notes.md' } }, - @{ Func='Invoke-MissingInProject'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','missing-in-project','Invoke-MissingInProjectCLI.ps1'); Args=@{ LVVersion='2021'; Arch='64'; ProjectFile='Proj.lvproj' } }, + @{ Func='Invoke-MissingInProject'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','missing-in-project','Invoke-MissingInProjectCLI.ps1'); Args=@{ LVVersion='2021'; SupportedBitness='64'; ProjectFile='Proj.lvproj' } }, @{ Func='Invoke-ModifyVIPBDisplayInfo'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','modify-vipb-display-info','ModifyVIPBDisplayInfo.ps1'); Args=@{ SupportedBitness='64'; RelativePath='.'; VIPBPath='dummy.vipb'; MinimumSupportedLVVersion='2021'; LabVIEWMinorRevision='2021'; Major=1; Minor=0; Patch=0; Build=1; Commit='abc'; DisplayInformationJSON='{}' } }, @{ Func='Invoke-PrepareLabVIEWSource'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','prepare-labview-source','Prepare_LabVIEW_source.ps1'); Args=@{ MinimumSupportedLVVersion='2021'; SupportedBitness='64'; RelativePath='.'; LabVIEW_Project='Proj'; Build_Spec='Spec' } }, @{ Func='Invoke-RenameFile'; Script=[System.IO.Path]::Combine($repoRoot,'scripts','rename-file','Rename-file.ps1'); Args=@{ CurrentFilename='a'; NewFilename='b' } }, diff --git a/tests/pester/RelativePath.Actions.Tests.ps1 b/tests/pester/RelativePath.Actions.Tests.ps1 index 9f704e67..12c99844 100644 --- a/tests/pester/RelativePath.Actions.Tests.ps1 +++ b/tests/pester/RelativePath.Actions.Tests.ps1 @@ -18,14 +18,15 @@ $meta = @{ Describe 'add-token-to-labview resolves RelativePath' { It 'dry-runs without warnings' -Tag 'REQ-003' { $params = Get-LabVIEWIconEditorArgsJson - $json = $params.ArgsJson + $obj = $params.ArgsJson | ConvertFrom-Json + $obj.RelativePath = './' + $json = $obj | ConvertTo-Json -Compress $projectRoot = $params.WorkingDirectory - $expected = ($json | ConvertFrom-Json).RelativePath $out = & $dispatcher -ActionName add-token-to-labview -ArgsJson $json -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $expected + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -35,12 +36,12 @@ Describe 'apply-vipc resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ MinimumSupportedLVVersion = $b.MinimumSupportedLVVersion; SupportedBitness = $b.SupportedBitness; RelativePath = $b.RelativePath; VIP_LVVersion = '2021'; VIPCPath = 'dummy.vipc' } | ConvertTo-Json -Compress + $args = @{ MinimumSupportedLVVersion = $b.MinimumSupportedLVVersion; SupportedBitness = $b.SupportedBitness; RelativePath = './'; VIP_LVVersion = '2021'; VIPCPath = 'dummy.vipc' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName apply-vipc -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -50,12 +51,12 @@ Describe 'build-vi-package resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; LabVIEWMinorRevision='2021'; RelativePath=$b.RelativePath; VIPBPath='dummy.vipb'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef'; DisplayInformationJSON='{}'; ReleaseNotesFile='notes.md' } | ConvertTo-Json -Compress + $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; LabVIEWMinorRevision='2021'; RelativePath='./'; VIPBPath='dummy.vipb'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef'; DisplayInformationJSON='{}'; ReleaseNotesFile='notes.md' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName build-vi-package -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -65,12 +66,12 @@ Describe 'build resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ RelativePath=$b.RelativePath; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef'; LabVIEWMinorRevision='2021'; CompanyName='Company'; AuthorName='Author' } | ConvertTo-Json -Compress + $args = @{ RelativePath='./'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef'; LabVIEWMinorRevision='2021'; CompanyName='Company'; AuthorName='Author' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName build -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -80,12 +81,12 @@ Describe 'build-lvlibp resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; RelativePath=$b.RelativePath; LabVIEW_Project='My.lvproj'; Build_Spec='MyBuild'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef' } | ConvertTo-Json -Compress + $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; RelativePath='./'; LabVIEW_Project='My.lvproj'; Build_Spec='MyBuild'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName build-lvlibp -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -95,12 +96,12 @@ Describe 'modify-vipb-display-info resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ SupportedBitness=$b.SupportedBitness; RelativePath=$b.RelativePath; VIPBPath='dummy.vipb'; MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; LabVIEWMinorRevision='2021'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef'; DisplayInformationJSON='{}'; ReleaseNotesFile='notes.md' } | ConvertTo-Json -Compress + $args = @{ SupportedBitness=$b.SupportedBitness; RelativePath='./'; VIPBPath='dummy.vipb'; MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; LabVIEWMinorRevision='2021'; Major=1; Minor=0; Patch=0; Build=1; Commit='deadbeef'; DisplayInformationJSON='{}'; ReleaseNotesFile='notes.md' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName modify-vipb-display-info -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -110,12 +111,12 @@ Describe 'prepare-labview-source resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; RelativePath=$b.RelativePath; LabVIEW_Project='My.lvproj'; Build_Spec='MyBuild' } | ConvertTo-Json -Compress + $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; RelativePath='./'; LabVIEW_Project='My.lvproj'; Build_Spec='MyBuild' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName prepare-labview-source -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -125,12 +126,12 @@ Describe 'restore-setup-lv-source resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; RelativePath=$b.RelativePath; LabVIEW_Project='My.lvproj'; Build_Spec='MyBuild' } | ConvertTo-Json -Compress + $args = @{ MinimumSupportedLVVersion=$b.MinimumSupportedLVVersion; SupportedBitness=$b.SupportedBitness; RelativePath='./'; LabVIEW_Project='My.lvproj'; Build_Spec='MyBuild' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName restore-setup-lv-source -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -140,12 +141,12 @@ Describe 'revert-development-mode resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ RelativePath=$b.RelativePath } | ConvertTo-Json -Compress + $args = @{ RelativePath='./' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName revert-development-mode -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -155,12 +156,12 @@ Describe 'set-development-mode resolves RelativePath' { $params = Get-LabVIEWIconEditorArgsJson $b = $params.ArgsJson | ConvertFrom-Json $projectRoot = $params.WorkingDirectory - $args = @{ RelativePath=$b.RelativePath } | ConvertTo-Json -Compress + $args = @{ RelativePath='./' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName set-development-mode -ArgsJson $args -WorkingDirectory $projectRoot -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 $jsonText = $jsonLine -replace '^[^{}]*({.*})','$1' - ($jsonText | ConvertFrom-Json).RelativePath | Should -Be $b.RelativePath + ($jsonText | ConvertFrom-Json).RelativePath | Should -Be '.' $out | Should -Not -Match 'Ignored unknown parameters' } } @@ -170,7 +171,7 @@ Describe 'RelativePath "." resolves with varying working directories' { It "dry-runs without warnings when WorkingDirectory is $subdir" -Tag 'REQ-003' { $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..' '..')).Path $workingDir = Join-Path $repoRoot $subdir - $args = @{ RelativePath = '.' } | ConvertTo-Json -Compress + $args = @{ RelativePath = './' } | ConvertTo-Json -Compress $out = & $dispatcher -ActionName set-development-mode -ArgsJson $args -WorkingDirectory $workingDir -DryRun *>&1 | Out-String $LASTEXITCODE | Should -Be 0 $jsonLine = $out -split "`n" | Where-Object { $_ -match '{' } | Select-Object -Last 1 diff --git a/tests/pester/ScriptPath.Tests.ps1 b/tests/pester/ScriptPath.Tests.ps1 index 4d4e1705..bfdfa7d3 100644 --- a/tests/pester/ScriptPath.Tests.ps1 +++ b/tests/pester/ScriptPath.Tests.ps1 @@ -11,7 +11,7 @@ $scriptRoot = Join-Path $repoRoot 'scripts' Import-Module (Join-Path $PSScriptRoot 'Helper' 'ArgsJson.psm1') $projectRoot = (Get-LabVIEWIconEditorArgsJson).WorkingDirectory $dispatcher = Join-Path $repoRoot 'actions' 'Invoke-OSAction.ps1' -$actionNames = pwsh -NoProfile -File $dispatcher -ListActions -WorkingDirectory $projectRoot | +$actionNames = & $dispatcher -ListActions -WorkingDirectory $projectRoot | Where-Object { $_ -match '^\s+- ' } | ForEach-Object { $_.Trim().Substring(2) }