From 4fda79056f7416000f0eedbc4c291044d1329c7b Mon Sep 17 00:00:00 2001 From: Pluze Zhu Date: Sat, 13 Jun 2026 13:36:09 -0500 Subject: [PATCH] refactor: simplify matlab batch entrypoint --- .../skills/labkit-codecheck-fixer/SKILL.md | 10 +- .agents/skills/labkit-test-planner/SKILL.md | 2 +- .github/workflows/matlab-tests.yml | 32 +--- AGENTS.md | 4 +- docs/README.md | 2 +- docs/testing.md | 54 ++---- scripts/matlab_batch.sh | 65 +++++++ scripts/run_matlab_tests.ps1 | 170 ------------------ scripts/run_matlab_tests.sh | 126 ------------- .../project/BuildTaskFrameworkGuardrailTest.m | 33 ++-- 10 files changed, 117 insertions(+), 381 deletions(-) create mode 100644 scripts/matlab_batch.sh delete mode 100644 scripts/run_matlab_tests.ps1 delete mode 100755 scripts/run_matlab_tests.sh diff --git a/.agents/skills/labkit-codecheck-fixer/SKILL.md b/.agents/skills/labkit-codecheck-fixer/SKILL.md index 3712baa..9fbbe7e 100644 --- a/.agents/skills/labkit-codecheck-fixer/SKILL.md +++ b/.agents/skills/labkit-codecheck-fixer/SKILL.md @@ -67,11 +67,11 @@ Coordinate with: 5. Run focused validation for the touched area. Examples: ```bash - scripts/run_matlab_tests.sh testLabkitBiosignal - scripts/run_matlab_tests.sh testLabkitDta - scripts/run_matlab_tests.sh testLabkitUi - scripts/run_matlab_tests.sh testAppsImageMeasurement - scripts/run_matlab_tests.sh testProject + buildtool testLabkitBiosignal + buildtool testLabkitDta + buildtool testLabkitUi + buildtool testAppsImageMeasurement + buildtool testProject ``` Pick the smallest source-aligned task that covers the behavior, adding diff --git a/.agents/skills/labkit-test-planner/SKILL.md b/.agents/skills/labkit-test-planner/SKILL.md index d842705..798db19 100644 --- a/.agents/skills/labkit-test-planner/SKILL.md +++ b/.agents/skills/labkit-test-planner/SKILL.md @@ -24,7 +24,7 @@ another skill already read shared AGENTS context, do not reread it. ## Task Routing Use the smallest source-aligned validation set that covers the touched -boundary. `docs/testing.md` owns the canonical build-task names, wrappers, and +boundary. `docs/testing.md` owns the canonical build-task names, CI scope, and command examples. ```text diff --git a/.github/workflows/matlab-tests.yml b/.github/workflows/matlab-tests.yml index fa52ed2..67e35ea 100644 --- a/.github/workflows/matlab-tests.yml +++ b/.github/workflows/matlab-tests.yml @@ -15,8 +15,8 @@ concurrency: cancel-in-progress: true jobs: - shell-wrapper: - name: Shell Wrapper Checks + repository-hygiene: + name: Repository Hygiene runs-on: ubuntu-latest timeout-minutes: 5 @@ -33,30 +33,14 @@ jobs: exit 1 fi - - name: Check Bash wrapper syntax - run: bash -n scripts/run_matlab_tests.sh + - name: Check MATLAB batch locator syntax + run: bash -n scripts/matlab_batch.sh - - name: Check Bash wrapper help - run: bash scripts/run_matlab_tests.sh --help + - name: Check MATLAB batch locator help + run: bash scripts/matlab_batch.sh --help - - name: Check Bash wrapper build task smoke - run: MATLAB_CMD=true bash scripts/run_matlab_tests.sh testProject - - - name: Check PowerShell wrapper parser - run: pwsh -NoProfile -Command '$null = [scriptblock]::Create((Get-Content -Raw -LiteralPath "scripts/run_matlab_tests.ps1"))' - - - name: Check PowerShell wrapper help - run: pwsh -NoProfile -File scripts/run_matlab_tests.ps1 --help - - - name: Check PowerShell wrapper build task smoke - run: pwsh -NoProfile -Command '$env:MATLAB_CMD="true"; ./scripts/run_matlab_tests.ps1 testProject' - - - name: Check removed selector flags are rejected - run: | - if bash scripts/run_matlab_tests.sh --suite; then - echo "Expected --suite to be rejected" - exit 1 - fi + - name: Check MATLAB batch locator smoke + run: MATLAB_CMD=true bash scripts/matlab_batch.sh "buildtool listTasks" quality: name: Quality Guardrails diff --git a/AGENTS.md b/AGENTS.md index 943c25a..1bf0e43 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -101,8 +101,8 @@ When using local lab files to reproduce a bug: Run relevant automated checks after executable MATLAB, test, fixture, package, or validation-rule changes. Use focused checks during iteration and the default non-GUI build task for broad changes. -Use `docs/testing.md` as the canonical command matrix for build tasks, wrapper -behavior, CI scope, fixture expectations, and GUI validation limits. Scoped +Use `docs/testing.md` as the canonical command matrix for build tasks, CI +scope, fixture expectations, and GUI validation limits. Scoped `AGENTS.md` files should only route by ownership and should not duplicate the full task list. diff --git a/docs/README.md b/docs/README.md index 2150f86..a92d3b4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +8,7 @@ These docs are written for people who run, maintain, or extend LabKit. Start wit | --- | --- | | `../README.md` | Project overview, app launch list, and the default validation entry point. | | `*.md` component docs | Human-readable behavior, architecture, public APIs, and maintenance contracts. | -| `testing.md` | The canonical build-task matrix, wrapper behavior, CI scope, fixture expectations, and GUI validation limits. | +| `testing.md` | The canonical build-task matrix, CI scope, fixture expectations, and GUI validation limits. | | `../AGENTS.md` and scoped `AGENTS.md` files | Future execution rules for agent work, ownership red lines, and routing rules. | | `../.agents/migration_guide.md` | Agent-facing migration debt ledger, current debt snapshot, and future debt-handling rules. | | `../.agents/skills/` | Task procedures for boundary checks, app building, migration planning, and validation routing. | diff --git a/docs/testing.md b/docs/testing.md index fd7e1b9..f48039a 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -68,24 +68,16 @@ Default non-GUI build task: buildtool test ``` -On Windows PowerShell: +If MATLAB is not on `PATH`, use the thin MATLAB locator: -```powershell -.\scripts\run_matlab_tests.ps1 test -``` - -If local execution policy blocks direct `.ps1` execution, run: - -```powershell -powershell -ExecutionPolicy Bypass -File .\scripts\run_matlab_tests.ps1 test +```bash +scripts/matlab_batch.sh "buildtool test" ``` -Both wrappers accept build task names only and call `buildtool`. Selector flags -such as `--suite`, `--test`, and `--gui` are not supported. Set `MATLAB_CMD` -when MATLAB is not on `PATH`, set `MATLAB_FLAGS` for MATLAB startup flags, and -set `MATLAB_TEST_LOG` to override the default `matlab_test.log` location. Run -`buildtool listTasks` or `scripts/run_matlab_tests.sh listTasks` to inspect the -current task catalog. +`scripts/matlab_batch.sh` only locates MATLAB, changes to the repository root, +and runs the supplied MATLAB `-batch` command. It does not parse test task names +or maintain a separate test interface. Set `MATLAB_CMD` when MATLAB is not on +`PATH`. Run `buildtool listTasks` to inspect the current task catalog. Advanced targeted debugging can call the internal runner directly: @@ -112,12 +104,12 @@ commands. | Focused GUI build tasks | Local MATLAB with graphics support | Noninteractive launch, layout, and callback wiring checks for selected app families. | | Manual GUI validation | User-run app windows | Interactive file selection, drawing, visual inspection, and full workflow feel. | -CI runs shell-wrapper, quality, unit, and integration jobs on pushes and pull -requests for every branch through `.github/workflows/matlab-tests.yml`. Manual and -scheduled CI runs also execute coverage, GUI structural, and non-blocking GUI -gesture jobs. Coverage is intentionally outside the default PR gate to keep PR -feedback focused and avoid duplicate test execution. Do not describe CI as full -interactive GUI workflow validation. +CI runs repository-hygiene, quality, unit, and integration jobs on pushes and +pull requests for every branch through `.github/workflows/matlab-tests.yml`. +Manual and scheduled CI runs also execute coverage, GUI structural, and +non-blocking GUI gesture jobs. Coverage is intentionally outside the default PR +gate to keep PR feedback focused and avoid duplicate test execution. Do not +describe CI as full interactive GUI workflow validation. Each MATLAB CI job writes a GitHub Step Summary with JUnit totals, artifact locations, the slowest test cases, and failed-test details when available. @@ -127,12 +119,12 @@ artifacts; GitHub Actions does not render artifact HTML inline, so interactive HTML browsing still requires downloading the artifact or adding a separate publishing target. -The shell-wrapper job owns repository-level checks that are cheaper and safer -outside MATLAB, including the rule that `LabKit.prj` and `resources/project/` -must stay untracked local IDE metadata. MATLAB build tasks should not shell out -to git for this repository-state check. CI jobs also use explicit job timeouts -so a MATLAB process hang fails quickly instead of consuming the GitHub Actions -six-hour default. +The repository-hygiene job owns repository-level checks that are cheaper and +safer outside MATLAB, including the rule that `LabKit.prj` and +`resources/project/` must stay untracked local IDE metadata. MATLAB build tasks +should not shell out to git for this repository-state check. CI jobs also use +explicit job timeouts so a MATLAB process hang fails quickly instead of +consuming the GitHub Actions six-hour default. ## Focused Build Tasks @@ -155,14 +147,6 @@ buildtool testGuiStructural buildtool testGuiGesture ``` -Use task names from Windows PowerShell: - -```powershell -.\scripts\run_matlab_tests.ps1 testLabkitDta -.\scripts\run_matlab_tests.ps1 testAppsElectrochem -.\scripts\run_matlab_tests.ps1 testGuiStructural -``` - Focused build tasks mirror source ownership: | Task | Use it for | diff --git a/scripts/matlab_batch.sh b/scripts/matlab_batch.sh new file mode 100644 index 0000000..e17a2b6 --- /dev/null +++ b/scripts/matlab_batch.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +usage() { + cat <<'USAGE' +Usage: scripts/matlab_batch.sh MATLAB_COMMAND + +Finds MATLAB, changes to the LabKit repository root, and runs MATLAB_COMMAND +with MATLAB -batch. + +Examples: + scripts/matlab_batch.sh "buildtool test" + scripts/matlab_batch.sh "buildtool testProject" + scripts/matlab_batch.sh "buildtool listTasks" + +Environment: + MATLAB_CMD Optional path or command name for MATLAB. +USAGE +} + +if [[ $# -ne 1 || "$1" == "-h" || "$1" == "--help" ]]; then + usage + if [[ $# -eq 1 && ( "$1" == "-h" || "$1" == "--help" ) ]]; then + exit 0 + fi + exit 2 +fi + +find_matlab() { + if [[ -n "${MATLAB_CMD:-}" ]]; then + printf '%s\n' "$MATLAB_CMD" + return 0 + fi + + if command -v matlab >/dev/null 2>&1; then + command -v matlab + return 0 + fi + + local candidate + for candidate in /Applications/MATLAB_*.app/bin/matlab; do + if [[ -x "$candidate" ]]; then + printf '%s\n' "$candidate" + return 0 + fi + done + + return 1 +} + +matlab_literal() { + local value="$1" + value="${value//\'/\'\'}" + printf "'%s'" "$value" +} + +MATLAB_BIN="$(find_matlab || true)" +if [[ -z "$MATLAB_BIN" ]]; then + echo "MATLAB executable not found. Set MATLAB_CMD=/path/to/matlab." >&2 + exit 127 +fi + +exec "$MATLAB_BIN" -batch "cd($(matlab_literal "$ROOT_DIR")); $1;" diff --git a/scripts/run_matlab_tests.ps1 b/scripts/run_matlab_tests.ps1 deleted file mode 100644 index b041610..0000000 --- a/scripts/run_matlab_tests.ps1 +++ /dev/null @@ -1,170 +0,0 @@ -<# -.SYNOPSIS -Runs LabKit MATLAB build tasks from Windows PowerShell. - -.DESCRIPTION -This is the Windows-native wrapper for the LabKit build task entry points. -With no task arguments it runs `buildtool test`. Positional arguments are passed -as build task names, for example `checkStyle` or `testUnit coverage`. -#> - -$ErrorActionPreference = 'Stop' - -$RootDir = Resolve-Path (Join-Path $PSScriptRoot '..') -$Tasks = @() - -function Show-Usage { - @' -Usage: .\scripts\run_matlab_tests.ps1 [TASK ...] - -Runs LabKit MATLAB build tasks. With no TASK arguments, runs `buildtool test`. - -Examples: - .\scripts\run_matlab_tests.ps1 - .\scripts\run_matlab_tests.ps1 checkStyle - .\scripts\run_matlab_tests.ps1 testUnit coverage - .\scripts\run_matlab_tests.ps1 testGuiStructural - .\scripts\run_matlab_tests.ps1 listTasks - -Task catalog: - See docs/testing.md or run `buildtool listTasks`. - -Removed interface: - --suite, --test, and --gui are no longer supported. Use build task names. - -Environment: - MATLAB_CMD Optional path or command name for MATLAB. - MATLAB_FLAGS Optional MATLAB flags for every run. - MATLAB_TEST_LOG Optional log path. Defaults to .\matlab_test.log. -'@ -} - -function Fail-Usage { - param( - [Parameter(Mandatory = $true)] - [string] $Message - ) - - Write-Host $Message - Show-Usage - exit 2 -} - -for ($i = 0; $i -lt $args.Count; $i++) { - $arg = [string] $args[$i] - if ($arg -in @('-h', '--help')) { - Show-Usage - exit 0 - } - if ($arg.StartsWith('-')) { - Fail-Usage "Unsupported option: $arg. Use build task names such as checkStyle, test, or testGuiStructural." - } - if ($arg -notmatch '^[A-Za-z][A-Za-z0-9_]*$') { - Fail-Usage "Invalid build task name: $arg" - } - $Tasks += $arg -} - -if ($Tasks.Count -eq 0) { - $Tasks = @('test') -} - -function Find-Matlab { - if (-not [string]::IsNullOrWhiteSpace($env:MATLAB_CMD)) { - return $env:MATLAB_CMD - } - - $cmd = Get-Command matlab.exe -ErrorAction SilentlyContinue - if ($null -ne $cmd -and -not [string]::IsNullOrWhiteSpace($cmd.Source)) { - return $cmd.Source - } - - $cmd = Get-Command matlab -ErrorAction SilentlyContinue - if ($null -ne $cmd -and -not [string]::IsNullOrWhiteSpace($cmd.Source)) { - return $cmd.Source - } - - $programFiles = $env:ProgramFiles - if ([string]::IsNullOrWhiteSpace($programFiles)) { - return $null - } - - $matlabRoot = Join-Path $programFiles 'MATLAB' - if (-not (Test-Path -LiteralPath $matlabRoot)) { - return $null - } - - $candidates = Get-ChildItem -LiteralPath $matlabRoot -Directory -ErrorAction SilentlyContinue | - Where-Object { $_.Name -like 'R*' } | - Sort-Object -Property Name -Descending - - foreach ($candidate in $candidates) { - $exe = Join-Path $candidate.FullName 'bin\matlab.exe' - if (Test-Path -LiteralPath $exe) { - return $exe - } - } - - return $null -} - -function ConvertTo-MatlabStringLiteral { - param( - [Parameter(Mandatory = $true)] - [string] $Value - ) - - return "'" + ($Value -replace "'", "''") + "'" -} - -function Split-MatlabFlags { - param( - [string] $Flags - ) - - if ([string]::IsNullOrWhiteSpace($Flags)) { - return @() - } - - return @($Flags -split '\s+' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) -} - -$MatlabBin = Find-Matlab -if ([string]::IsNullOrWhiteSpace($MatlabBin)) { - Write-Host 'MATLAB executable not found. Set MATLAB_CMD to matlab.exe and retry.' - exit 127 -} - -$rootPath = [string] $RootDir -$logFile = if (-not [string]::IsNullOrWhiteSpace($env:MATLAB_TEST_LOG)) { - $env:MATLAB_TEST_LOG -} else { - Join-Path $rootPath 'matlab_test.log' -} - -$taskText = $Tasks -join ' ' -$matlabCommand = "cd($(ConvertTo-MatlabStringLiteral $rootPath)); buildtool $taskText;" -$matlabArgs = @(Split-MatlabFlags $env:MATLAB_FLAGS) -$matlabArgs += @('-logfile', $logFile, '-batch', $matlabCommand) - -Write-Host "Using MATLAB: $MatlabBin" -Write-Host "Project root: $rootPath" -Write-Host "Build tasks: $taskText" -Write-Host "MATLAB log: $logFile" - -if (Test-Path -LiteralPath $logFile) { - Remove-Item -LiteralPath $logFile -Force -} - -& $MatlabBin @matlabArgs -$status = $LASTEXITCODE - -if ($status -eq 0) { - Write-Host "MATLAB build tasks completed successfully. Log: $logFile" -} elseif (Test-Path -LiteralPath $logFile) { - Get-Content -LiteralPath $logFile -Raw -} else { - Write-Host "MATLAB did not create log file: $logFile" -} - -exit $status diff --git a/scripts/run_matlab_tests.sh b/scripts/run_matlab_tests.sh deleted file mode 100755 index d03e17f..0000000 --- a/scripts/run_matlab_tests.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -TASKS=() - -usage() { - cat <<'USAGE' -Usage: scripts/run_matlab_tests.sh [TASK ...] - -Runs LabKit MATLAB build tasks. With no TASK arguments, runs `buildtool test`. - -Examples: - scripts/run_matlab_tests.sh - scripts/run_matlab_tests.sh checkStyle - scripts/run_matlab_tests.sh testUnit coverage - scripts/run_matlab_tests.sh testGuiStructural - scripts/run_matlab_tests.sh listTasks - -Task catalog: - See docs/testing.md or run `buildtool listTasks`. - -Removed interface: - --suite, --test, and --gui are no longer supported. Use build task names. - -Environment: - MATLAB_CMD Optional path or command name for MATLAB. - MATLAB_FLAGS Optional MATLAB flags for every run. - MATLAB_TEST_LOG Optional log path. Defaults to ./matlab_test.log. -USAGE -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -*) - echo "Unsupported option: $1. Use build task names such as checkStyle, test, or testGuiStructural." >&2 - usage >&2 - exit 2 - ;; - *) - if [[ ! "$1" =~ ^[A-Za-z][A-Za-z0-9_]*$ ]]; then - echo "Invalid build task name: $1" >&2 - usage >&2 - exit 2 - fi - TASKS+=("$1") - shift - ;; - esac -done - -if [[ ${#TASKS[@]} -eq 0 ]]; then - TASKS=(test) -fi - -find_matlab() { - if [[ -n "${MATLAB_CMD:-}" ]]; then - printf '%s\n' "$MATLAB_CMD" - return 0 - fi - - if command -v matlab >/dev/null 2>&1; then - command -v matlab - return 0 - fi - - local candidate - for candidate in /Applications/MATLAB_*.app/bin/matlab; do - if [[ -x "$candidate" ]]; then - printf '%s\n' "$candidate" - return 0 - fi - done - - return 1 -} - -matlab_literal() { - local value="$1" - value="${value//\'/\'\'}" - printf "'%s'" "$value" -} - -MATLAB_BIN="$(find_matlab || true)" -if [[ -z "$MATLAB_BIN" ]]; then - echo "MATLAB executable not found. Set MATLAB_CMD=/path/to/matlab and retry." >&2 - exit 127 -fi - -LOG_FILE="${MATLAB_TEST_LOG:-$ROOT_DIR/matlab_test.log}" -TASK_TEXT="${TASKS[*]}" - -echo "Using MATLAB: $MATLAB_BIN" -echo "Project root: $ROOT_DIR" -echo "Build tasks: $TASK_TEXT" -echo "MATLAB log: $LOG_FILE" - -MATLAB_FLAG_ARGS=() -if [[ -n "${MATLAB_FLAGS:-}" ]]; then - read -r -a MATLAB_FLAG_ARGS <<< "$MATLAB_FLAGS" -fi - -rm -f "$LOG_FILE" - -set +e -if [[ ${#MATLAB_FLAG_ARGS[@]} -gt 0 ]]; then - "$MATLAB_BIN" "${MATLAB_FLAG_ARGS[@]}" -logfile "$LOG_FILE" -batch "cd($(matlab_literal "$ROOT_DIR")); buildtool $TASK_TEXT;" -else - "$MATLAB_BIN" -logfile "$LOG_FILE" -batch "cd($(matlab_literal "$ROOT_DIR")); buildtool $TASK_TEXT;" -fi -status=$? -set -e - -if [[ "$status" -eq 0 ]]; then - echo "MATLAB build tasks completed successfully. Log: $LOG_FILE" -elif [[ -f "$LOG_FILE" ]]; then - cat "$LOG_FILE" -else - echo "MATLAB did not create log file: $LOG_FILE" >&2 -fi - -exit "$status" diff --git a/tests/integration/project/BuildTaskFrameworkGuardrailTest.m b/tests/integration/project/BuildTaskFrameworkGuardrailTest.m index 2e35ade..d77f32d 100644 --- a/tests/integration/project/BuildTaskFrameworkGuardrailTest.m +++ b/tests/integration/project/BuildTaskFrameworkGuardrailTest.m @@ -15,7 +15,7 @@ function buildTaskCatalogMatchesTaskFunctions(testCase) 'Build task catalog entries should carry non-empty descriptions.'); end - function documentedAndWrapperTasksStayInCatalog(testCase) + function documentedBuildTasksStayInCatalog(testCase) root = setupLabKitTestPath(); catalog = extractBuildfileCatalog(root); catalogNames = catalog.Name; @@ -36,18 +36,13 @@ function documentedAndWrapperTasksStayInCatalog(testCase) "Documented buildtool tasks in " + relativePath(root, docFiles(k))); end - wrapperFiles = [ ... - fullfile(root, "scripts", "run_matlab_tests.sh"), ... - fullfile(root, "scripts", "run_matlab_tests.ps1")]; - for k = 1:numel(wrapperFiles) - wrapper = string(fileread(wrapperFiles(k))); - testCase.verifyFalse(contains(wrapper, "Common tasks:"), ... - "Wrappers should not duplicate the task matrix: " + ... - relativePath(root, wrapperFiles(k))); - testCase.verifyTrue(contains(wrapper, "buildtool listTasks"), ... - "Wrappers should route task discovery to the build catalog: " + ... - relativePath(root, wrapperFiles(k))); - end + batchLocator = string(fileread(fullfile(root, "scripts", ... + "matlab_batch.sh"))); + formerWrapperName = "run_" + "matlab_tests"; + testCase.verifyFalse(contains(batchLocator, formerWrapperName), ... + 'MATLAB locator should not reintroduce the former test wrapper.'); + testCase.verifyFalse(contains(batchLocator, "TASK"), ... + 'MATLAB locator should not parse or own build task names.'); end function focusedBuildTasksMatchAtLeastOneTest(testCase) @@ -139,14 +134,18 @@ function ciRepositoryStateChecksStayOutsideMatlab(testCase) workflowPath = fullfile(root, ".github", "workflows", ... "matlab-tests.yml"); workflow = string(fileread(workflowPath)); - shellWrapperJob = extractWorkflowJob(workflow, "shell-wrapper"); + repositoryHygieneJob = extractWorkflowJob(workflow, ... + "repository-hygiene"); - testCase.verifyTrue(contains(shellWrapperJob, ... + testCase.verifyTrue(contains(repositoryHygieneJob, ... "Check MATLAB Project metadata is local"), ... - 'Repository metadata checks should run in shell-wrapper.'); - testCase.verifyTrue(contains(shellWrapperJob, ... + 'Repository metadata checks should run in repository-hygiene.'); + testCase.verifyTrue(contains(repositoryHygieneJob, ... "git ls-files -- LabKit.prj resources/project"), ... 'Tracked MATLAB Project metadata should be checked by git in shell.'); + formerWrapperPath = "scripts/run_" + "matlab_tests"; + testCase.verifyFalse(contains(repositoryHygieneJob, formerWrapperPath), ... + 'CI should not require the former test wrapper scripts.'); testCase.verifyFalse(contains(workflow, "matlabProjectMetadataStaysLocal"), ... 'MATLAB tests should not shell out to git for repository metadata.'); end