diff --git a/actions/OpenSourceActions.psd1 b/actions/OpenSourceActions.psd1 index 184cc1eb..c13345cd 100644 --- a/actions/OpenSourceActions.psd1 +++ b/actions/OpenSourceActions.psd1 @@ -26,6 +26,7 @@ 'Invoke-RunPesterTests' 'Invoke-RunUnitTests' 'Invoke-SetDevelopmentMode' + 'Invoke-ViaLvDocker' ) PrivateData = @{ diff --git a/actions/OpenSourceActions.psm1 b/actions/OpenSourceActions.psm1 index 7e0e374f..b8218ef5 100644 --- a/actions/OpenSourceActions.psm1 +++ b/actions/OpenSourceActions.psm1 @@ -489,3 +489,33 @@ function Invoke-SetDevelopmentMode { $args = @{ RelativePath = $RelativePath } return Invoke-OpenSourceActionScript -ScriptSegments @('set-development-mode','Set_Development_Mode.ps1') -Arguments $args -DryRun:$DryRun -gcliPath $gcliPath } + +# Runs VI Analyzer tests using LabVIEW Docker container. +# ConfigPath: Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb). If empty, generates from changed files. +# TemplatePath: Path to .viancfg template (required when generating config dynamically). +# BaseBranch: Branch to compare against for changed files (used when generating config). +# LabviewVersion: LabVIEW Docker image version tag. +# DockerImage: Full Docker image name. +# DryRun: If set, prints the command instead of executing it. +# gcliPath: Optional path prepended to PATH for locating the g CLI. +function Invoke-ViaLvDocker { + [CmdletBinding()] + param( + [Parameter()] [string] $ConfigPath = '', + [Parameter()] [string] $TemplatePath = '', + [Parameter()] [string] $BaseBranch = 'origin/develop', + [Parameter()] [string] $LabviewVersion = '2026q1-linux', + [Parameter()] [string] $DockerImage = 'nationalinstruments/labview', + [Parameter()] [switch] $DryRun, + [Parameter()] [string] $gcliPath + ) + Write-Information "Executing ViaLvDocker (DryRun=$DryRun)" + $args = @{ + ConfigPath = $ConfigPath + TemplatePath = $TemplatePath + BaseBranch = $BaseBranch + LabviewVersion = $LabviewVersion + DockerImage = $DockerImage + } + return Invoke-OpenSourceActionScript -ScriptSegments @('via-lv-docker','RunViaLvDocker.ps1') -Arguments $args -DryRun:$DryRun -gcliPath $gcliPath +} \ No newline at end of file diff --git a/artifacts/linux/action-docs.json b/artifacts/linux/action-docs.json index 7bbf8583..a8ea0dbd 100644 --- a/artifacts/linux/action-docs.json +++ b/artifacts/linux/action-docs.json @@ -612,6 +612,51 @@ } } }, + "Invoke-ViaLvDocker": { + "description": "Runs VI Analyzer tests using LabVIEW Docker container. ConfigPath: Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb). If empty, generates from changed files. TemplatePath: Path to .viancfg template (required when generating config dynamically). BaseBranch: Branch to compare against for changed files (used when generating config). LabviewVersion: LabVIEW Docker image version tag. DockerImage: Full Docker image name. DryRun: If set, prints the command instead of executing it. gcliPath: Optional path prepended to PATH for locating the g CLI.", + "parameters": { + "BaseBranch": { + "type": "string", + "required": false, + "default": "origin/develop", + "description": "Branch to compare against for changed files (used when generating config)" + }, + "ConfigPath": { + "type": "string", + "required": false, + "default": "", + "description": "Path to VI Analyzer configuration file (" + }, + "DockerImage": { + "type": "string", + "required": false, + "default": "nationalinstruments/labview", + "description": "Full Docker image name" + }, + "DryRun": { + "type": "boolean", + "required": false, + "description": "If set, prints the command instead of executing it" + }, + "gcliPath": { + "type": "string", + "required": false, + "description": "Optional path prepended to PATH for locating the g CLI" + }, + "LabviewVersion": { + "type": "string", + "required": false, + "default": "2026q1-linux", + "description": "LabVIEW Docker image version tag" + }, + "TemplatePath": { + "type": "string", + "required": false, + "default": "", + "description": "Path to" + } + } + }, "Normalize-RelativePath": { "description": "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.", "parameters": { @@ -1623,6 +1668,64 @@ "type": "string" } ], - "setup-mkdocs": [] + "setup-mkdocs": [], + "via-lv-docker": [ + { + "name": "config_path", + "description": "Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb)", + "required": false, + "default": "", + "type": "string" + }, + { + "name": "template_path", + "description": "Path to .viancfg template (required to generate config file dynamically)", + "required": false, + "default": "", + "type": "string" + }, + { + "name": "base_branch", + "description": "Branch to compare against for changed files (used when generating config)", + "required": false, + "default": "origin/develop", + "type": "string" + }, + { + "name": "labview_version", + "description": "LabVIEW Docker image version tag", + "required": false, + "default": "2026q1-linux", + "type": "string" + }, + { + "name": "docker_image", + "description": "Full Docker image name", + "required": false, + "default": "nationalinstruments/labview", + "type": "string" + }, + { + "name": "working_directory", + "description": "Working directory where the action will run.", + "required": false, + "default": "", + "type": "string" + }, + { + "name": "log_level", + "description": "Verbosity level (ERROR|WARN|INFO|DEBUG).", + "required": false, + "default": "INFO", + "type": "string" + }, + { + "name": "dry_run", + "description": "If true, simulate the action without side effects.", + "required": false, + "default": false, + "type": "string" + } + ] } } \ No newline at end of file diff --git a/artifacts/linux/action-docs.md b/artifacts/linux/action-docs.md index 729aa768..e81556da 100644 --- a/artifacts/linux/action-docs.md +++ b/artifacts/linux/action-docs.md @@ -254,6 +254,22 @@ Configures the repository for development mode. RelativePath: Normalized path to pwsh ./actions/Invoke-OSAction.ps1 -ActionName Invoke-SetDevelopmentMode -ArgsJson '{}' ``` +#### Invoke-ViaLvDocker +Runs VI Analyzer tests using LabVIEW Docker container. ConfigPath: Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb). If empty, generates from changed files. TemplatePath: Path to .viancfg template (required when generating config dynamically). BaseBranch: Branch to compare against for changed files (used when generating config). LabviewVersion: LabVIEW Docker image version tag. DockerImage: Full Docker image name. DryRun: If set, prints the command instead of executing it. gcliPath: Optional path prepended to PATH for locating the g CLI. +| Parameter | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| BaseBranch | string | false | origin/develop | Branch to compare against for changed files (used when generating config) | +| ConfigPath | string | false | | Path to VI Analyzer configuration file ( | +| DockerImage | string | false | nationalinstruments/labview | Full Docker image name | +| DryRun | boolean | false | | If set, prints the command instead of executing it | +| LabviewVersion | string | false | 2026q1-linux | LabVIEW Docker image version tag | +| TemplatePath | string | false | | Path to | +| gcliPath | string | false | | Optional path prepended to PATH for locating the g CLI | + +```powershell +pwsh ./actions/Invoke-OSAction.ps1 -ActionName Invoke-ViaLvDocker -ArgsJson '{}' +``` + #### Normalize-RelativePath 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. | Parameter | Type | Required | Default | Description | @@ -479,4 +495,16 @@ pwsh ./actions/Invoke-OSAction.ps1 -ActionName Set-LogLevel -ArgsJson '{}' #### setup-mkdocs | Name | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | \ No newline at end of file +| --- | --- | --- | --- | --- | + +#### via-lv-docker +| Name | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| config_path | string | false | | Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb) | +| template_path | string | false | | Path to .viancfg template (required to generate config file dynamically) | +| base_branch | string | false | origin/develop | Branch to compare against for changed files (used when generating config) | +| labview_version | string | false | 2026q1-linux | LabVIEW Docker image version tag | +| docker_image | string | false | nationalinstruments/labview | Full Docker image name | +| working_directory | string | false | | Working directory where the action will run. | +| log_level | string | false | INFO | Verbosity level (ERROR|WARN|INFO|DEBUG). | +| dry_run | string | false | false | If true, simulate the action without side effects. | \ No newline at end of file diff --git a/dispatchers.json b/dispatchers.json index 1dbf753c..d0245b78 100644 --- a/dispatchers.json +++ b/dispatchers.json @@ -610,6 +610,51 @@ } } }, + "Invoke-ViaLvDocker": { + "description": "Runs VI Analyzer tests using LabVIEW Docker container. ConfigPath: Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb). If empty, generates from changed files. TemplatePath: Path to .viancfg template (required when generating config dynamically). BaseBranch: Branch to compare against for changed files (used when generating config). LabviewVersion: LabVIEW Docker image version tag. DockerImage: Full Docker image name. DryRun: If set, prints the command instead of executing it. gcliPath: Optional path prepended to PATH for locating the g CLI.", + "parameters": { + "BaseBranch": { + "type": "string", + "required": false, + "default": "origin/develop", + "description": "Branch to compare against for changed files (used when generating config)" + }, + "ConfigPath": { + "type": "string", + "required": false, + "default": "", + "description": "Path to VI Analyzer configuration file (" + }, + "DockerImage": { + "type": "string", + "required": false, + "default": "nationalinstruments/labview", + "description": "Full Docker image name" + }, + "DryRun": { + "type": "boolean", + "required": false, + "description": "If set, prints the command instead of executing it" + }, + "gcliPath": { + "type": "string", + "required": false, + "description": "Optional path prepended to PATH for locating the g CLI" + }, + "LabviewVersion": { + "type": "string", + "required": false, + "default": "2026q1-linux", + "description": "LabVIEW Docker image version tag" + }, + "TemplatePath": { + "type": "string", + "required": false, + "default": "", + "description": "Path to" + } + } + }, "Normalize-RelativePath": { "description": "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.", "parameters": { diff --git a/docs/actions/via-lv-docker.md b/docs/actions/via-lv-docker.md new file mode 100644 index 00000000..f1a036b5 --- /dev/null +++ b/docs/actions/via-lv-docker.md @@ -0,0 +1,88 @@ +# via-lv-docker + +## Purpose + +Execute LabVIEW VI Analyzer tests using a Docker container and parse results. Supports both static configuration files and dynamic config generation based on changed files in pull requests. + +## Parameters + +Common parameters are described in [Common parameters](../common-parameters.md). + +### Required + +None. All parameters have default values. + +### Optional + +- **ConfigPath** (`string`): Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi/ .ctl/ .llb). If empty, generates config from changed files. +- **TemplatePath** (`string`): Path to .viancfg template (required when generating config dynamically). +- **BaseBranch** (`string`): Branch to compare against for changed files (used when generating config). Default: `origin/develop`. +- **LabviewVersion** (`string`): LabVIEW Docker image version tag. Default: `2026q1-linux`. +- **DockerImage** (`string`): Full Docker image name. Default: `nationalinstruments/labview`. + +### GitHub Action inputs + +GitHub Action inputs are provided in `snake_case`, while CLI parameters use `PascalCase`. The table below maps each input to its corresponding CLI parameter. For details on shared CLI flags, see [Common parameters](../common-parameters.md). + +| Input | CLI parameter | Description | +| --- | --- | --- | +| `config_path` | `ConfigPath` | Path to VI Analyzer configuration file (.viancfg). | +| `template_path` | `TemplatePath` | Path to .viancfg template. | +| `base_branch` | `BaseBranch` | Branch to compare against for changed files. | +| `labview_version` | `LabviewVersion` | LabVIEW Docker image version tag. | +| `docker_image` | `DockerImage` | Full Docker image name. | +| `working_directory` | `WorkingDirectory` | Directory where the action runs. | +| `log_level` | `LogLevel` | Verbosity level (ERROR\|WARN\|INFO\|DEBUG). | +| `dry_run` | `DryRun` | If true, simulate the action without side effects. | + +## Examples + +### CLI + +```powershell +pwsh -File actions/Invoke-OSAction.ps1 -ActionName via-lv-docker -ArgsJson '{ + "ConfigPath": "my-config.viancfg", + "LabviewVersion": "2026q1-linux" +}' +``` + +### GitHub Action - Static Config + +```yaml +- name: Run VI Analyzer + uses: ni/open-source/via-lv-docker@v1 + with: + config_path: '.github/via-config.viancfg' + labview_version: '2026q1-linux' +``` + +### GitHub Action - Dynamic Config from Changed Files + +This is useful to have for PR checks. + +```yaml +- name: Run VI Analyzer on Changed Files + uses: ni/open-source/via-lv-docker@v1 + with: + base_branch: 'origin/${{ github.event.pull_request.base.ref }}' + template_path: '.github/via_template.viancfg' +``` + +## Outputs + +- **vi-analyzer-report.htm**: HTML report generated by VI Analyzer +- Console output with parsed test results showing passes, failures, and errors + +## Return Codes + +- `0` – all VI Analyzer tests passed +- non‑zero – tests failed or analyzer error + +See [via-lv-docker/action.yml](../../via-lv-docker/action.yml) and [scripts/via-lv-docker/RunViaLvDocker.ps1](../../scripts/via-lv-docker/RunViaLvDocker.ps1) for implementation details. + +For troubleshooting tips, see the [troubleshooting guide](../troubleshooting.md). + +## See also + +- [Workflow documentation](../workflows/via-lv-docker.md) +- [scripts/via-lv-docker/README.md](../../scripts/via-lv-docker/README.md) diff --git a/docs/index.md b/docs/index.md index cbd664aa..7e0c06e8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,6 +37,7 @@ Open Source LabVIEW Actions unifies LabVIEW [CI/CD](glossary.md#ci-cd) scripts b | [run-unit-tests](actions/run-unit-tests.md) | Run LabVIEW unit tests via the LabVIEW Unit Test Framework CLI and report pass/fail/error using standard exit codes. | | [set-development-mode](actions/set-development-mode.md) | Configure the repository for development mode by removing packed libraries, adding tokens, preparing sources, and closing LabVIEW. | | [setup-mkdocs](actions/setup-mkdocs.md) | Install a pinned MkDocs with caching. | +| [via-lv-docker](actions/via-lv-docker.md) | Execute LabVIEW VI Analyzer tests using a Docker container and parse results. | ## Workflow Examples @@ -59,3 +60,4 @@ Open Source LabVIEW Actions unifies LabVIEW [CI/CD](glossary.md#ci-cd) scripts b | [run-unit-tests](workflows/run-unit-tests.md) | Run LabVIEW unit tests via the LabVIEW Unit Test Framework CLI and report pass/fail/error using standard exit codes. | | [set-development-mode](workflows/set-development-mode.md) | Configure the repository for development mode by removing packed libraries, adding tokens, preparing sources, and closing LabVIEW. | | [setup-mkdocs](workflows/setup-mkdocs.md) | Install a pinned MkDocs with caching. | +| [via-lv-docker](workflows/via-lv-docker.md) | Execute LabVIEW VI Analyzer tests using a Docker container and parse results. | diff --git a/docs/workflows/via-lv-docker.md b/docs/workflows/via-lv-docker.md new file mode 100644 index 00000000..d011d0c3 --- /dev/null +++ b/docs/workflows/via-lv-docker.md @@ -0,0 +1,72 @@ +# via-lv-docker workflow + +## Purpose + +Dispatch the [via-lv-docker](../actions/via-lv-docker.md) action to a target repository through `Invoke-OSAction.ps1`. + +## Parameters + +### Inputs + +| Parameter | Description | +| --- | --- | +| `repository` | Repository in `owner/repo` format to operate on. | +| `ref` | Branch or tag to check out. Defaults to `main`. | + +### Secrets + +| Secret | Description | +| --- | --- | +| `REPO_TOKEN` | Personal access token with permission to read the target repository. | + +## Examples + +```yaml +name: via-lv-docker +on: + workflow_dispatch: + inputs: + repository: + description: 'owner/repo of the repository to target' + required: true + ref: + description: 'Branch or tag to check out' + required: false + default: 'main' +jobs: + via-lv-docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Checkout target repository + uses: actions/checkout@v4 + with: + repository: ${{ inputs.repository }} + ref: ${{ inputs.ref }} + path: target + token: ${{ secrets.REPO_TOKEN }} + - name: Run VI Analyzer + shell: pwsh + run: | + ./actions/Invoke-OSAction.ps1 -ActionName via-lv-docker -WorkingDirectory "${{ github.workspace }}/target" -ArgsJson '{ + "ConfigPath": "", + "BaseBranch": "origin/develop", + "LabviewVersion": "2026q1-linux", + "DockerImage": "nationalinstruments/labview" + }' + - name: Upload VI Analyzer Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: vi-analyzer-report + path: target/vi-analyzer-report.htm +``` +After the workflow completes, the VI Analyzer HTML report will be available as an artifact. + +## Return Codes + +- N/A + +## See also + +- [Action documentation](../actions/via-lv-docker.md) diff --git a/mkdocs.yml b/mkdocs.yml index 2042f86c..09448f77 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,6 +67,7 @@ nav: - Run Unit Tests: actions/run-unit-tests.md - Set Development Mode: actions/set-development-mode.md - Setup MkDocs: actions/setup-mkdocs.md + - VIA LV Docker: actions/via-lv-docker.md - Scripts: - Add Token to LabVIEW: scripts/add-token-to-labview.md - Apply VIPC: scripts/apply-vipc.md @@ -103,6 +104,7 @@ nav: - Run Unit Tests: workflows/run-unit-tests.md - Set Development Mode: workflows/set-development-mode.md - Setup MkDocs: workflows/setup-mkdocs.md + - VIA LV Docker: workflows/via-lv-docker.md - Developer Docs: - Adapter Authoring: adapter-authoring.md - Versioning: versioning.md diff --git a/requirements.json b/requirements.json index a25a40cf..37ae8126 100644 --- a/requirements.json +++ b/requirements.json @@ -260,6 +260,14 @@ "SelfHosted.Workflow.Tests" ] }, + { + "id": "REQ-034", + "description": "Workflow tests the composite action defined in via-lv-docker/action.yml on the GitHub-hosted Ubuntu runner labeled ubuntu-latest.", + "runner": "ubuntu-latest", + "tests": [ + "ViaLvDocker.Workflow" + ] + }, { "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'.", diff --git a/scripts/via-lv-docker/README.md b/scripts/via-lv-docker/README.md new file mode 100644 index 00000000..f9944771 --- /dev/null +++ b/scripts/via-lv-docker/README.md @@ -0,0 +1,246 @@ +# LabVIEW VI Analyzer GitHub Action + +A GitHub Action that runs LabVIEW VI Analyzer tests in a Docker container and parses the results. Supports both static configuration files and dynamic config generation based on changed files in pull requests. + +## Features + +- **Containerized Testing**: Runs VI Analyzer in official LabVIEW Docker containers +- **Dynamic Config Generation**: Automatically analyzes only changed `.vi`, `.ctl`, and `.llb` files in PRs +- **Static Configuration**: Use pre-defined VI Analyzer configs for manual runs or specific test suites +- **Detailed Reporting**: Parses and displays test results, failures, and errors in console output +- **Flexible**: Works with both automated PR testing and manual workflow triggers + +## Prerequisites + +- Repository with LabVIEW code (`.vi`, `.ctl`, `.llb` files) +- GitHub-hosted runner (Ubuntu) or self-hosted runner with Docker support +- Access to `nationalinstruments/labview` Docker images + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `config-path` | Path to existing VI Analyzer config file (`.viancfg`). If not provided, will generate from changed files. | No | `''` | +| `template-path` | Path to `.viancfg` template (used when generating dynamic config) | No | `.github/actions/via-lv-docker/via_template_linux.viancfg` | +| `base-branch` | Branch to compare against for changed files (used when generating config) | No | `origin/develop` | +| `labview-version` | LabVIEW Docker image version tag | No | `2026q1-linux` | +| `docker-image` | Full Docker image name | No | `nationalinstruments/labview` | + +## Outputs + +| Output | Description | +|--------|-------------| +| `via-exit-code` | VI Analyzer exit code (0 = success, non-zero = failures/errors) | +| `report-path` | Path to generated HTML report (`vi-analyzer-report.htm`) | +| `config-used` | Path to the config file that was used | + +## Usage Examples + +### Scenario 1: PR Testing (Dynamic Config) + +Automatically test only changed LabVIEW files in pull requests: + +```yaml +name: VI Analyzer Tests + +on: + pull_request: + branches: [main, develop] + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for git diff + + - name: Run VI Analyzer + uses: ni/open-source/via-lv-docker@v1 + with: + base-branch: origin/${{ github.event.pull_request.base.ref }} + + - name: Upload Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: vi-analyzer-report + path: vi-analyzer-report.htm +``` + +### Scenario 2: Manual Testing (Static Config) + +Use a pre-defined configuration for manual workflow runs: + +```yaml +name: VI Analyzer Tests + +on: + workflow_dispatch: + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run VI Analyzer + uses: ni/open-source/via-lv-docker@v1 + with: + config-path: '.github/via-config.viancfg' + + - name: Upload Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: vi-analyzer-report + path: vi-analyzer-report.htm +``` + +### Scenario 3: Combined Workflow + +Support both PR-based dynamic testing and manual runs with static config: + +```yaml +name: VI Analyzer Tests + +on: + pull_request: + branches: [main, develop] + push: + branches: [main, develop] + workflow_dispatch: + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run VI Analyzer + uses: ni/open-source/via-lv-docker@v1 + with: + # Use static config for manual triggers, dynamic for PRs + config-path: ${{ github.event_name == 'workflow_dispatch' && '.github/via-config.viancfg' || '' }} + base-branch: origin/${{ github.event.pull_request.base.ref || 'develop' }} + + - name: Upload Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: vi-analyzer-report + path: vi-analyzer-report.htm +``` + +### Scenario 4: Custom LabVIEW Version + +Test with a specific LabVIEW version: + +```yaml +- name: Run VI Analyzer + uses: ni/open-source/labview-via-action@v1 + with: + labview-version: '2025q3-linux' + config-path: '.github/via-config.viancfg' +``` + +## How It Works + +1. **Config Determination**: + - If `config-path` is provided and exists → use it + - Otherwise → generate config from changed files via `git diff` + +2. **Dynamic Config Generation** (when no config provided): + - Compares current branch against `base-branch` + - Finds all changed `.vi`, `.ctl`, `.llb` files + - Generates `.viancfg` file with only those files + - Skips if no LabVIEW files changed + +3. **Docker Execution**: + - Pulls specified LabVIEW Docker image + - Mounts workspace and scripts + - Runs `LabVIEWCLI` with VI Analyzer operation + - Generates HTML report + +4. **Report Parsing**: + - Extracts statistics (VIs analyzed, tests passed/failed) + - Parses and displays detailed errors: + - Failed test details + - VI not loadable errors + - Test errors (password-protected VIs, etc.) + +## Creating a Static Config File + +For manual testing, create `.github/via-config.viancfg`: + +```xml + + + + true + + + + ".." + FALSE + + + + +``` + +## Console Output Example + +```plain text +================================================== + VI Analyzer Results +================================================== + +VIs Analyzed: 417 +Total Tests: 187000 +Passed: 184868 +Failed: 2132 +Skipped: 0 + +================================================== + Failed Tests Summary +================================================== + + MyVI.vi +--- + Panel Size and Position + → This VI's front panel does not reside entirely within the specified bounds + +================================================== + Test Error Out Errors +================================================== + +[Wire Sources] + Post Build Icon Editor PPL.vi + → Error 1040. VI is password protected... +``` + +## Supported LabVIEW Versions + +This action uses the official National Instruments LabVIEW Docker images: + +- `2026q1-linux` (default) +- `latest-linux` +- `2025q3-linux` + +Check [Docker Hub](https://hub.docker.com/r/nationalinstruments/labview) for available versions. + +## Troubleshooting + +### No Config Generated + +If you see "No LabVIEW files changed; skipping VI Analyzer tests": + +- Ensure you're using `fetch-depth: 0` in checkout +- Verify changed files match `.vi`, `.ctl`, or `.llb` extensions +- Check the `base-branch` is correct diff --git a/scripts/via-lv-docker/RunViaLvDocker.ps1 b/scripts/via-lv-docker/RunViaLvDocker.ps1 new file mode 100644 index 00000000..1f50f2a8 --- /dev/null +++ b/scripts/via-lv-docker/RunViaLvDocker.ps1 @@ -0,0 +1,138 @@ +<# +.SYNOPSIS + Run VI Analyzer tests using LabVIEW Docker container. + +.DESCRIPTION + Executes LabVIEW VI Analyzer tests in a Docker container and parses results. + Supports both static configuration files and dynamic config generation based on changed files. + +.PARAMETER ConfigPath + Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb). If empty, will generate from changed files. + +.PARAMETER TemplatePath + Path to .viancfg template (required when generating config dynamically). + +.PARAMETER BaseBranch + Branch to compare against for changed files (used when generating config). + +.PARAMETER LabviewVersion + LabVIEW Docker image version tag. + +.PARAMETER DockerImage + Full Docker image name. + +.NOTES + Requires Docker and bash. The LabVIEW Docker container does not include PowerShell. +#> + +param( + [Parameter(Mandatory=$false)] + [string] + $ConfigPath = '', + + [Parameter(Mandatory=$false)] + [string] + $TemplatePath = '', + + [Parameter(Mandatory=$false)] + [string] + $BaseBranch = 'origin/develop', + + [Parameter(Mandatory=$false)] + [string] + $LabviewVersion = '2026q1-linux', + + [Parameter(Mandatory=$false)] + [string] + $DockerImage = 'nationalinstruments/labview' +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# Get the path to the bash scripts +$viaDockerPath = $PSScriptRoot +$generateScript = Join-Path $viaDockerPath 'generate_viancfg.sh' +$runViaScript = Join-Path $viaDockerPath 'run-via.sh' +$parseReportScript = Join-Path $viaDockerPath 'parse-via-report.sh' + +# Determine config strategy +$configToUse = $ConfigPath +$shouldGenerate = $false + +if ([string]::IsNullOrWhiteSpace($ConfigPath) -or -not (Test-Path $ConfigPath)) { + Write-Information "Will generate config from changed files" -InformationAction Continue + $configToUse = 'generated-config.viancfg' + $shouldGenerate = $true + + # Use default template path if not provided + if ([string]::IsNullOrWhiteSpace($TemplatePath)) { + $TemplatePath = Join-Path $viaDockerPath 'via_template_linux.viancfg' + } +} else { + Write-Information "Using provided config file: $ConfigPath" -InformationAction Continue +} + +# Generate VI Analyzer config if needed +if ($shouldGenerate) { + Write-Information "Generating VI Analyzer config from template: $TemplatePath" -InformationAction Continue + + if (-not (Test-Path $generateScript)) { + throw "Generate script not found: $generateScript" + } + + bash $generateScript ` + --template-path $TemplatePath ` + --output-path $configToUse ` + --target-branch $BaseBranch + + if ($LASTEXITCODE -ne 0) { + throw "Failed to generate VI Analyzer config (exit code: $LASTEXITCODE)" + } + + if (-not (Test-Path $configToUse)) { + Write-Information "No LabVIEW files changed. Skipping VI Analyzer tests." -InformationAction Continue + exit 0 + } +} + +# Validate config exists +if (-not (Test-Path $configToUse)) { + throw "Config file not found at: $configToUse" +} + +Write-Information "Using config: $configToUse" -InformationAction Continue + +# Pull LabVIEW Docker image +Write-Information "Pulling Docker image: ${DockerImage}:${LabviewVersion}" -InformationAction Continue +docker pull "${DockerImage}:${LabviewVersion}" + +if ($LASTEXITCODE -ne 0) { + throw "Failed to pull Docker image (exit code: $LASTEXITCODE)" +} + +# Run VI Analyzer in container +Write-Information "Running VI Analyzer in Docker container..." -InformationAction Continue + +$workspaceMount = "${PWD}:/workspace" +$scriptMount = "${runViaScript}:/tmp/run-via.sh" + +docker run --rm ` + -v $workspaceMount ` + -v $scriptMount ` + "${DockerImage}:${LabviewVersion}" ` + bash -c "chmod +x /tmp/run-via.sh && /tmp/run-via.sh '$configToUse'" + +$viaExitCode = $LASTEXITCODE +Write-Information "VI Analyzer exit code: $viaExitCode" -InformationAction Continue + +# Parse VI Analyzer report +if (Test-Path $parseReportScript) { + Write-Information "Parsing VI Analyzer report..." -InformationAction Continue + & bash $parseReportScript $viaExitCode 2>&1 | Write-Information -InformationAction Continue +} else { + Write-Warning "Report parsing script not found: $parseReportScript. Skipping report parsing." +} + +# Exit with VI Analyzer's exit code +exit $viaExitCode \ No newline at end of file diff --git a/scripts/via-lv-docker/generate_viancfg.sh b/scripts/via-lv-docker/generate_viancfg.sh new file mode 100644 index 00000000..00f5054b --- /dev/null +++ b/scripts/via-lv-docker/generate_viancfg.sh @@ -0,0 +1,103 @@ +#!/bin/bash +set -e + +# Parse arguments +TEMPLATE_PATH="" +OUTPUT_PATH="" +TARGET_BRANCH="origin/develop" + +while [[ $# -gt 0 ]]; do + case $1 in + --template-path) + TEMPLATE_PATH="$2" + shift 2 + ;; + --output-path) + OUTPUT_PATH="$2" + shift 2 + ;; + --target-branch) + TARGET_BRANCH="$2" + shift 2 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + +# Validate required parameters +if [ -z "$TEMPLATE_PATH" ] || [ -z "$OUTPUT_PATH" ]; then + echo "Error: --template-path and --output-path are required" + exit 1 +fi + +echo "Generating VI Analyzer config from template: $TEMPLATE_PATH" +echo "Target branch: $TARGET_BRANCH" +echo "" + +# Get changed LabVIEW files relative to the target branch +mapfile -t CHANGED_FILES < <(git diff --name-only "$TARGET_BRANCH" --diff-filter=d | grep -E '\.(vi|ctl|llb)$' || true) + +if [ ${#CHANGED_FILES[@]} -eq 0 ]; then + echo "No LabVIEW files changed. Skipping config generation." + exit 0 +fi + +echo "Found ${#CHANGED_FILES[@]} changed LabVIEW file(s):" +printf '%s\n' "${CHANGED_FILES[@]}" +echo "" + +# Get Git root directory +GIT_ROOT=$(git rev-parse --show-toplevel) + +# Read template XML and prepare output +cp "$TEMPLATE_PATH" "$OUTPUT_PATH" + +OUTPUT_DIR=$(dirname "$OUTPUT_PATH") +if [ -n "$OUTPUT_DIR" ] && [ ! -d "$OUTPUT_DIR" ]; then + mkdir -p "$OUTPUT_DIR" +fi + +# Get the absolute path of the output config for relative path calculation +OUTPUT_ABS_DIR=$(cd "$OUTPUT_DIR" && pwd) + +# Create a temporary file for the items +ITEMS_FILE=$(mktemp) + +for file in "${CHANGED_FILES[@]}"; do + # Construct absolute path + ABSOLUTE_FILE_PATH="$GIT_ROOT/$file" + + # Calculate relative path from output config to the VI + RELATIVE_PATH=$(realpath --relative-to="$OUTPUT_ABS_DIR" "$ABSOLUTE_FILE_PATH") + + FORMATTED_PATH="\"$RELATIVE_PATH\"" + + # Write XML item to temp file + cat >> "$ITEMS_FILE" << EOF + + $FORMATTED_PATH + FALSE + +EOF +done + +# Use awk to insert the items into the template +awk -v items_file="$ITEMS_FILE" ' + /<\/ItemsToAnalyze>/ { + while ((getline line < items_file) > 0) { + print line + } + close(items_file) + } + //,/<\/Item>/ { next } + { print } +' "$TEMPLATE_PATH" > "$OUTPUT_PATH" + +# Clean up temp file +rm -f "$ITEMS_FILE" + +echo "" +echo "Generated config at $OUTPUT_PATH with ${#CHANGED_FILES[@]} items." \ No newline at end of file diff --git a/scripts/via-lv-docker/parse-via-report.sh b/scripts/via-lv-docker/parse-via-report.sh new file mode 100644 index 00000000..e8ca6490 --- /dev/null +++ b/scripts/via-lv-docker/parse-via-report.sh @@ -0,0 +1,210 @@ +#!/bin/bash +set -e +VIA_EXIT_CODE="${1:-0}" + +if [ ! -f "vi-analyzer-report.htm" ]; then + echo "No VI Analyzer report found" + exit $VIA_EXIT_CODE +fi + +echo "" +echo "==================================================" +echo " VI Analyzer Results" +echo "==================================================" +echo "" + +# Extract results +VIS_ANALYZED=$(grep -oP 'VIs Analyzed\K[0-9]+' vi-analyzer-report.htm || echo "0") +TESTS_RUN=$(grep -oP 'Total Tests Run\K[0-9]+' vi-analyzer-report.htm || echo "0") +PASSED=$(grep -oP 'Passed Tests\K[0-9]+' vi-analyzer-report.htm || echo "0") +FAILED=$(grep -oP 'Failed Tests\K[0-9]+' vi-analyzer-report.htm || echo "0") +SKIPPED=$(grep -oP 'Skipped Tests\K[0-9]+' vi-analyzer-report.htm || echo "0") + +# Extract error counts +VI_NOT_LOADABLE=$(grep -oP 'VI not loadable\K[0-9]+' vi-analyzer-report.htm || echo "0") +TEST_NOT_LOADABLE=$(grep -oP 'Test not loadable\K[0-9]+' vi-analyzer-report.htm || echo "0") +TEST_NOT_RUNNABLE=$(grep -oP 'Test not runnable\K[0-9]+' vi-analyzer-report.htm || echo "0") +TEST_ERROR_OUT=$(grep -oP 'Test error out\K[0-9]+' vi-analyzer-report.htm || echo "0") + +echo "VIs Analyzed: $VIS_ANALYZED" +echo "Total Tests: $TESTS_RUN" +echo "Passed: $PASSED" +echo "Failed: $FAILED" +echo "Skipped: $SKIPPED" +echo "" + +if [ "$FAILED" -gt 0 ]; then + echo "==================================================" + echo " Failed Tests Summary" + echo "==================================================" + + # Extract failed test details + awk ' + /Failed Tests/,/Testing Errors/ { + if (match($0, /([^<]+\.vi)<\/b>/, arr)) { + if (vi_name) print "" + vi_name = arr[1] + printf "\n %s\n", vi_name + print "---" + } + if (match($0, /([^<]+)<\/td>([^<]+)<\/td><\/tr>/, arr)) { + test_name = arr[1] + failure_msg = arr[2] + printf " %s\n → %s\n", test_name, failure_msg + } + } + ' vi-analyzer-report.htm + echo "" + HAS_ERRORS=1 +fi + +if [ "$VI_NOT_LOADABLE" -gt 0 ]; then + echo "==================================================" + echo " VI Not Loadable Errors" + echo "==================================================" + + awk ' + /

VI Not Loadable<\/h3>/,/<\/table>/ { + # Extract all table rows from the line + line = $0 + while (match(line, /([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td><\/tr>/, arr)) { + vi_name = arr[1] + vi_path = arr[2] + error_msg = arr[3] + printf "\n %s\n", vi_name + printf " Path: %s\n", vi_path + printf " → %s\n", error_msg + # Remove the matched portion and continue + line = substr(line, RSTART + RLENGTH) + } + } + ' vi-analyzer-report.htm + echo "" + HAS_ERRORS=1 +fi + +if [ "$TEST_NOT_LOADABLE" -gt 0 ]; then + echo "==================================================" + echo " Test Not Loadable Errors" + echo "==================================================" + + awk ' + /

Test Not Loadable<\/h3>/ { in_section = 1; next } + in_section && /

/ { exit } + in_section && /
([^<]+)<\/b>/ { + match($0, /
([^<]+)<\/b>/, arr) + if (current_test != "") print "" + current_test = arr[1] + printf "\n[%s]\n", current_test + next + } + in_section && // { + # Extract all table rows from this line and subsequent lines + line = $0 + # Keep reading lines until we hit
or next section + while (line !~ /<\/table>/ && getline nextline > 0) { + line = line nextline + if (line ~ /<\/table>/) break + } + # Now process all rows in the accumulated line + while (match(line, /([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td><\/tr>/, arr)) { + vi_name = arr[1] + vi_path = arr[2] + error_msg = arr[3] + printf " %s\n", vi_name + printf " → %s\n", error_msg + line = substr(line, RSTART + RLENGTH) + } + } + ' vi-analyzer-report.htm + echo "" + HAS_ERRORS=1 +fi + +if [ "$TEST_NOT_RUNNABLE" -gt 0 ]; then + echo "==================================================" + echo " Test Not Runnable Errors" + echo "==================================================" + + awk ' + /

Test Not Runnable<\/h3>/ { in_section = 1; next } + in_section && /

/ { exit } + in_section && /
([^<]+)<\/b>/ { + match($0, /
([^<]+)<\/b>/, arr) + if (current_test != "") print "" + current_test = arr[1] + printf "\n[%s]\n", current_test + next + } + in_section && // { + # Extract all table rows from this line and subsequent lines + line = $0 + # Keep reading lines until we hit
or next section + while (line !~ /<\/table>/ && getline nextline > 0) { + line = line nextline + if (line ~ /<\/table>/) break + } + # Now process all rows in the accumulated line + while (match(line, /([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td><\/tr>/, arr)) { + vi_name = arr[1] + vi_path = arr[2] + error_msg = arr[3] + printf " %s\n", vi_name + printf " → %s\n", error_msg + line = substr(line, RSTART + RLENGTH) + } + } + ' vi-analyzer-report.htm + echo "" + HAS_ERRORS=1 +fi + +if [ "$TEST_ERROR_OUT" -gt 0 ]; then + echo "==================================================" + echo " Test Error Out Errors" + echo "==================================================" + + awk ' + /

Test Error Out<\/h3>/ { in_section = 1; next } + in_section && /

/ { exit } + in_section && /
([^<]+)<\/b>/ { + match($0, /
([^<]+)<\/b>/, arr) + if (current_test != "") print "" + current_test = arr[1] + printf "\n[%s]\n", current_test + next + } + in_section && // { + # Extract all table rows from this line and subsequent lines + line = $0 + # Keep reading lines until we hit
or next section + while (line !~ /<\/table>/ && getline nextline > 0) { + line = line nextline + if (line ~ /<\/table>/) break + } + # Now process all rows in the accumulated line + while (match(line, /([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td><\/tr>/, arr)) { + vi_name = arr[1] + vi_path = arr[2] + error_msg = arr[3] + printf " %s\n", vi_name + printf " → %s\n", error_msg + line = substr(line, RSTART + RLENGTH) + } + } + ' vi-analyzer-report.htm + echo "" + HAS_ERRORS=1 +fi + +if [ "$HAS_ERRORS" -eq 1 ]; then + echo "" + echo "==================================================" + echo "See full report in artifacts for complete details." + echo "==================================================" +else + echo " All tests passed!" + echo "==================================================" +fi + +exit $VIA_EXIT_CODE \ No newline at end of file diff --git a/scripts/via-lv-docker/run-via.sh b/scripts/via-lv-docker/run-via.sh new file mode 100644 index 00000000..21c623de --- /dev/null +++ b/scripts/via-lv-docker/run-via.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -e + +# VI Analyzer script for GitHub Actions + +# Accept config path as first argument, default to generated-config.viancfg +CONFIG_PATH="${1:-generated-config.viancfg}" +ABSOLUTE_CONFIG="/workspace/$CONFIG_PATH" +ABSOLUTE_REPORT="/workspace/vi-analyzer-report.htm" +LV_YEAR="${LV_YEAR:-2025}" +LABVIEW_PATH="/usr/local/natinst/LabVIEW-${LV_YEAR}-64/labview" + +# Verify that the configuration path exists +if [ ! -d "$ABSOLUTE_CONFIG" ] && [ ! -f "$ABSOLUTE_CONFIG" ]; then + echo "Error: Configuration path not found at $ABSOLUTE_CONFIG" + exit 1 +fi + +echo "Running LabVIEWCLI VIAnalyzer with the following parameters:" +echo "ConfigPath: $ABSOLUTE_CONFIG" +echo "ReportPath: $ABSOLUTE_REPORT" +echo "LabVIEWPath: $LABVIEW_PATH" +echo "" + +# Run VI Analyzer +LabVIEWCLI \ + -OperationName RunVIAnalyzer \ + -ConfigPath "$ABSOLUTE_CONFIG" \ + -ReportPath "$ABSOLUTE_REPORT" \ + -ReportSaveType HTML \ + -LabVIEWPath "$LABVIEW_PATH" \ + -Headless \ No newline at end of file diff --git a/scripts/via-lv-docker/via_template_linux.viancfg b/scripts/via-lv-docker/via_template_linux.viancfg new file mode 100644 index 00000000..a59f9236 --- /dev/null +++ b/scripts/via-lv-docker/via_template_linux.viancfg @@ -0,0 +1,1057 @@ + + +1 +FALSE +"/" +0 + + + "." + FALSE + + + + + "Arrays and Strings in Loops" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Arrays and Strings in Loops.llb" + TRUE + + + + + "Coercion Dots" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Coercion Dots.llb" + TRUE + + + + + "Enabled Debugging" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Enabled Debugging.llb" + TRUE + + + + + "In Place Element Structure Usage" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/In Place Element Structure Usage.llb" + TRUE + + + + + "Inlinable VIs" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Inlinable VIs.llb" + TRUE + + + + + "Parallel For Loop Debugging" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Parallel For Loop Debugging.llb" + TRUE + + + + + "Parallelizable Loops" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Parallelizable Loops.llb" + TRUE + + + + + "Prepend Scalar With Build Array" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Prepend Scalar With Build Array.llb" + TRUE + + + + + "Redundant Boolean Operations" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Redundant Boolean Operations.llb" + TRUE + + + + + "Value Property Usage" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Value Property Usage.llb" + TRUE + + + + + "Wait in While Loop" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Wait in While Loop.llb" + TRUE + + + + + "Wired Terminals in Subdiagrams" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Performance/Wired Terminals in Subdiagrams.llb" + TRUE + + + + + "Array Constant Style" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Array Constant Style.llb" + TRUE + + + + + "Backwards Wires" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Backwards Wires.llb" + TRUE + + + + + "Case Structure Default Frame" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Case Structure Default Frame.llb" + TRUE + + + + + "Code Simplification" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Code Simplification.llb" + TRUE + + + + + "Control Terminal Label Visible" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Control Terminal Label Visible.llb" + TRUE + + + + + "Control Terminal Wiring" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Control Terminal Wiring.llb" + TRUE + + + + + "Diagram Disable Structures" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Diagram Disable Structures.llb" + TRUE + + + + + "Mixed Terminal Styles" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Mixed Terminal Styles.llb" + TRUE + + + + + "Poor Names of Enum Items" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Poor Names of Enum Items.llb" + TRUE + + + + + "Sequence Structure Usage" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Sequence Structure Usage.llb" + TRUE + + + + + "String Constant Style" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/String Constant Style.llb" + TRUE + + + + + "Tunnel Position" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Tunnel Position.llb" + TRUE + + + + + "Unused Code" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Unused Code.llb" + TRUE + + + + + "Wire Bends" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Wire Bends.llb" + TRUE + + + + + "Wire Crossings" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Wire Crossings.llb" + TRUE + + + + + "Wires Under Objects" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Style/Wires Under Objects.llb" + TRUE + + + + + "Adding Array Size Elements" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Adding Array Size Elements.llb" + TRUE + + + + + "Array Sum and Product Overflow" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Array Sum and Product Overflow.llb" + TRUE + + + + + "Breakpoint Detection" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Breakpoint Detection.llb" + TRUE + + + + + "Bundling Duplicate Names" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Bundling Duplicate Names.llb" + TRUE + + + + + "Case Structure with String Range" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Case Structure with String Range.llb" + TRUE + + + + + "Error Cluster Wired" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Error Cluster Wired.llb" + TRUE + + + + + "Find Deprecated Items" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Find Deprecated Items.llb" + TRUE + + + + + "For Loop Error Handling" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/For Loop Error Handling.llb" + TRUE + + + + + "For Loop Iteration Count" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/For Loop Iteration Count.llb" + TRUE + + + + + "For Loop Reference Handling" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/For Loop Reference Handling.llb" + TRUE + + + + + "Globals and Locals" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Globals and Locals.llb" + TRUE + + + + + "Hidden Objects in Structures" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Hidden Objects in Structures.llb" + TRUE + + + + + "Hidden Tunnels" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Hidden Tunnels.llb" + TRUE + + + + + "Indexer Datatype" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Indexer Datatype.llb" + TRUE + + + + + "Pattern Label" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Pattern Label.llb" + TRUE + + + + + "Reentrant VI Issues" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Reentrant VI Issues.llb" + TRUE + + + + + "Type Casting References" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Type Casting References.llb" + TRUE + + + + + "Unwired I32 Error" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Block Diagram/Warnings/Unwired I32 Error.llb" + TRUE + + + + + "Cyclomatic Complexity" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Complexity Metrics/Cyclomatic Complexity.llb" + TRUE + + + + + "Depth of Nesting of Structures" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Complexity Metrics/Depth of Nesting of Structures.llb" + TRUE + + + + + "Fan In" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Complexity Metrics/Fan In.llb" + TRUE + + + + + "Fan Out" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Complexity Metrics/Fan Out.llb" + TRUE + + + + + "Modularity Index" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Complexity Metrics/Modularity Index.llb" + TRUE + + + + + "Approved Bookmark Tags" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Documentation/Developer/Approved Bookmark Tags.llb" + TRUE + + + + + "Comment Usage" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Documentation/Developer/Comment Usage.llb" + TRUE + + + + + "Label Call Library Nodes" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Documentation/Developer/Label Call Library Nodes.llb" + TRUE + + + + + "Revision History" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Documentation/Developer/Revision History.llb" + TRUE + + + + + "Spell Check" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Documentation/User/Spell Check.llb" + TRUE + + + + + "VI Documentation" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Documentation/User/VI Documentation.llb" + TRUE + + + + + "Array Default Values" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/SubVI/Array Default Values.llb" + TRUE + + + + + "Cluster Sized to Fit" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/SubVI/Cluster Sized to Fit.llb" + TRUE + + + + + "Control Alignment" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/SubVI/Control Alignment.llb" + TRUE + + + + + "Alignment Grid Setting" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Alignment Grid Setting.llb" + TRUE + + + + + "Clipped Text" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Clipped Text.llb" + TRUE + + + + + "Dialog Controls" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Dialog Controls.llb" + TRUE + + + + + "Duplicate Control Labels" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Duplicate Control Labels.llb" + TRUE + + + + + "Empty List Items" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Empty List Items.llb" + TRUE + + + + + "Font Usage" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Font Usage.llb" + TRUE + + + + + "Overlapping Controls" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Overlapping Controls.llb" + TRUE + + + + + "Panel Size and Position" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Panel Size and Position.llb" + TRUE + + + + + "Scalar Chart Updates" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Scalar Chart Updates.llb" + TRUE + + + + + "Synchronous Display" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Synchronous Display.llb" + TRUE + + + + + "Transparent Labels" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/Front Panel/User Interface/Transparent Labels.llb" + TRUE + + + + + "SubVI and TypeDef Locations" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/File Properties/SubVI and TypeDef Locations.llb" + TRUE + + + + + "VI Extension" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/File Properties/VI Extension.llb" + TRUE + + + + + "VI Name" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/File Properties/VI Name.llb" + TRUE + + + + + "VI Saved Version" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/File Properties/VI Saved Version.llb" + TRUE + + + + + "VI Size" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/File Properties/VI Size.llb" + TRUE + + + + + "Connector Pane Alignment" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Connector Pane Alignment.llb" + TRUE + + + + + "Connector Pane Pattern" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Connector Pane Pattern.llb" + TRUE + + + + + "Default Icon" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Default Icon.llb" + TRUE + + + + + "Error Style" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Error Style.llb" + TRUE + + + + + "Full Connector Pane" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Full Connector Pane.llb" + TRUE + + + + + "Icon Size and Border" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Icon Size and Border.llb" + TRUE + + + + + "Polymorphic Terminals" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Polymorphic Terminals.llb" + TRUE + + + + + "Terminal Connection Type" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Terminal Connection Type.llb" + TRUE + + + + + "Terminal Positions" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/Icon and Connector Pane/Terminal Positions.llb" + TRUE + + + + + "Auto Error Handling Enabled" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Auto Error Handling Enabled.llb" + TRUE + + + + + "Broken VI" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Broken VI.llb" + TRUE + + + + + "Built Application Compatibility" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Built Application Compatibility.llb" + TRUE + + + + + "Control VI Type" + 1 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Control VI Type.llb" + TRUE + + + + + "Driver Usage" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Driver Usage.llb" + TRUE + + + + + "Platform Portability" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Platform Portability.llb" + TRUE + + + + + "Removed Diagram" + 2 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Removed Diagram.llb" + TRUE + + + + + "Separate Compiled Code Setting" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Separate Compiled Code Setting.llb" + TRUE + + + + + "Toolkit Usage" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/Toolkit Usage.llb" + TRUE + + + + + "VI Lock State" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/General/VI Properties/VI Lock State.llb" + TRUE + + + + + "Connector Inputs and Outputs" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Connector Inputs and Outputs.llb" + TRUE + + + + + "Controls and Indicators" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Controls and Indicators.llb" + TRUE + + + + + "Diagram Count" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Diagram Count.llb" + TRUE + + + + + "Diagram Size" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Diagram Size.llb" + TRUE + + + + + "Node Count" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Node Count.llb" + TRUE + + + + + "Property Reads and Writes" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Property Reads and Writes.llb" + TRUE + + + + + "Shared Library Calls" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Shared Library Calls.llb" + TRUE + + + + + "Structure Count" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Structure Count.llb" + TRUE + + + + + "Wire Sources" + 0 + 5 + "LabVIEW" + "project/_VI Analyzer/_tests/VI Metrics/Wire Sources.llb" + TRUE + + + + + + + \ No newline at end of file diff --git a/tests/pester/ViaLvDocker.Workflow.Tests.ps1 b/tests/pester/ViaLvDocker.Workflow.Tests.ps1 new file mode 100644 index 00000000..db82d507 --- /dev/null +++ b/tests/pester/ViaLvDocker.Workflow.Tests.ps1 @@ -0,0 +1,37 @@ +#requires -Version 7.0 +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +Describe 'ViaLvDocker.Workflow' { + $meta = @{ + requirement = 'REQ-034' + Owner = 'DevTools' + Evidence = 'tests/pester/ViaLvDocker.Workflow.Tests.ps1' + } + + It 'runs via-lv-docker action on ubuntu-latest runner [REQ-034]' -Tag 'REQ-034' { + $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..' '..')).Path + $actionPath = Join-Path $repoRoot 'via-lv-docker/action.yml' + + # Verify action.yml exists + $actionPath | Should -Exist + + # Parse action.yml + $actionContent = Get-Content -Raw $actionPath + $actionContent | Should -Not -BeNullOrEmpty + + # Verify key inputs are defined + $actionContent | Should -Match 'config_path:' + $actionContent | Should -Match 'template_path:' + $actionContent | Should -Match 'base_branch:' + $actionContent | Should -Match 'labview_version:' + $actionContent | Should -Match 'docker_image:' + + # Verify it uses composite action pattern + $actionContent | Should -Match "using: 'composite'" + + # Verify it calls the dispatcher + $actionContent | Should -Match 'common-dispatch.ps1' + $actionContent | Should -Match "ActionName = 'via-lv-docker'" + } +} \ No newline at end of file diff --git a/via-lv-docker/action.yml b/via-lv-docker/action.yml new file mode 100644 index 00000000..a4785692 --- /dev/null +++ b/via-lv-docker/action.yml @@ -0,0 +1,60 @@ +name: 'Run VI Analyzer with LabVIEW Container' +description: 'Execute LabVIEW VI Analyzer tests using Docker container and parse results' + +inputs: + config_path: + description: 'Path to VI Analyzer configuration file (.viancfg) or LabVIEW files (.vi, .ctl, .llb)' + required: false + default: '' + template_path: + description: 'Path to .viancfg template (required to generate config file dynamically)' + required: false + default: '' + base_branch: + description: 'Branch to compare against for changed files (used when generating config)' + required: false + default: 'origin/develop' + labview_version: + description: 'LabVIEW Docker image version tag' + required: false + default: '2026q1-linux' + docker_image: + description: 'Full Docker image name' + required: false + default: 'nationalinstruments/labview' + working_directory: + description: 'Working directory where the action will run.' + required: false + log_level: + description: 'Verbosity level (ERROR|WARN|INFO|DEBUG).' + default: 'INFO' + required: false + dry_run: + description: 'If true, simulate the action without side effects.' + default: false + required: false + +runs: + using: 'composite' + steps: + - name: Dispatch via-lv-docker + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $args = @{ + ConfigPath = '${{ inputs.config_path }}' + TemplatePath = '${{ inputs.template_path }}' + BaseBranch = '${{ inputs.base_branch }}' + LabviewVersion = '${{ inputs.labview_version }}' + DockerImage = '${{ inputs.docker_image }}' + } + $params = @{ + ActionName = 'via-lv-docker' + Args = $args + LogLevel = '${{ inputs.log_level }}' + } + if ('${{ inputs.dry_run }}' -eq 'true') { $params['DryRun'] = $true } + if ('${{ inputs.working_directory }}') { $params['WorkingDirectory'] = '${{ inputs.working_directory }}' } + $script = Join-Path $env:GITHUB_ACTION_PATH '..' 'actions' 'common-dispatch.ps1' + & $script @params + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } \ No newline at end of file