diff --git a/.github/actions/check-code/action.yml b/.github/actions/check-code/action.yml
deleted file mode 100644
index 77e9921..0000000
--- a/.github/actions/check-code/action.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-# Should only be used in a job where MATLAB and MatBox is installed in previous steps
-
-name: 'Check code and upload report'
-description: 'Analyse code for code issues and upload code issues report to GitHub'
-
-inputs:
- code_directory:
- description: 'Which folder to run the code check on'
- required: false
- default: './code'
- tools_directory:
- description: 'Where the codecheckToolbox function is located'
- required: false
- default: './tools'
-
-runs:
- using: "composite"
- steps:
- - name: Check for MATLAB code issues
- uses: matlab-actions/run-command@v2
- if: always()
- with:
- command: |
- addpath(genpath("${{ inputs.tools_directory }}"));
- if exist("codecheckToolbox", "file")
- codecheckToolbox();
- else
- matbox.tasks.codecheckToolbox(pwd, ...
- "FoldersToCheck", "${{ inputs.code_directory }}");
- end
-
- - name: Upload SARIF file
- uses: github/codeql-action/upload-sarif@v3
- continue-on-error: true # Will fail for MATLAB release < R2023a
- with:
- sarif_file: docs/reports/code_issues.sarif
diff --git a/.github/actions/install-matbox/action.yml b/.github/actions/install-matbox/action.yml
deleted file mode 100644
index 0a72a35..0000000
--- a/.github/actions/install-matbox/action.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: 'Install MatBox'
-description: 'Install MatBox in MATLAB on GitHub runner'
-inputs:
- mode: # mode of installation: release or commit, i.e install latest released version or use latest commit
- description: 'Which installation mode to use'
- required: true
- default: 'commit'
-runs:
- using: "composite"
- steps:
- - name: Install MatBox
- uses: matlab-actions/run-command@v2
- with:
- command: |
- addpath( "${{ github.action_path }}" )
- installMatBox( "${{ inputs.mode }}" )
-
- - name: Confirm installation of MatBox
- uses: matlab-actions/run-command@v2
- with:
- command: |
- versionStr = matbox.toolboxversion();
- assert(~isempty(versionStr), 'Failed to install MatBox.');
diff --git a/.github/actions/install-matbox/installMatBox.m b/.github/actions/install-matbox/installMatBox.m
deleted file mode 100644
index 68223be..0000000
--- a/.github/actions/install-matbox/installMatBox.m
+++ /dev/null
@@ -1,45 +0,0 @@
-function installMatBox(mode)
-% installMatBox - Install MatBox from latest release or latest commit
-
- arguments
- mode (1,1) string {mustBeMember(mode, ["release", "commit"])} = "release"
- end
-
- if mode == "release"
- installFromRelease() % local function
- elseif mode == "commit"
- installFromCommit() % local function
- end
-end
-
-function installFromRelease()
- addonsTable = matlab.addons.installedAddons();
- isMatchedAddon = addonsTable.Name == "MatBox";
-
- if ~isempty(isMatchedAddon) && any(isMatchedAddon)
- matlab.addons.enableAddon('MatBox')
- else
- info = webread('https://api.github.com/repos/ehennestad/MatBox/releases/latest');
- assetNames = {info.assets.name};
- isMltbx = startsWith(assetNames, 'MatBox');
-
- mltbx_URL = info.assets(isMltbx).browser_download_url;
-
- % Download matbox
- tempFilePath = websave(tempname, mltbx_URL);
- cleanupObj = onCleanup(@(fp) delete(tempFilePath));
-
- % Install toolbox
- matlab.addons.install(tempFilePath);
- end
-end
-
-function installFromCommit()
-
- scriptPath = mfilename('fullpath');
- projectFolder = extractBefore(scriptPath, fullfile('.github', 'actions'));
- codeDirectory = fullfile(projectFolder, 'code');
-
- addpath(genpath(codeDirectory))
- savepath()
-end
diff --git a/.github/actions/push-badges/action.yml b/.github/actions/push-badges/action.yml
deleted file mode 100644
index 67df8b9..0000000
--- a/.github/actions/push-badges/action.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-name: 'Push GitHub badges'
-description: 'Push badges for use on GitHub and located in .github/badges if there are detected changes.'
-
-inputs:
- pr-ref:
- description: "Branch ref to check out"
- required: true
- pr-repo:
- description: "Repository (owner/repo) to check out from"
- required: true
-
-runs:
- using: "composite"
- steps:
- # Check out the actual source branch in a separate working tree
- - name: Checkout PR branch for pushing badges
- uses: actions/checkout@v4
- with:
- ref: ${{ inputs.pr-ref }}
- repository: ${{ inputs.pr-repo }}
- path: pr-branch
-
- # Copy generated files to actual branch
- - name: Copy badges to PR branch
- shell: bash
- run: |
- cp -r .github/badges/* pr-branch/.github/badges/ 2>/dev/null || echo "No badges to copy"
-
- # Commit updated SVG badges for the issues and tests (if changed)
- - name: Commit and push SVG badges if updated
- working-directory: pr-branch
- shell: bash
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git fetch
-
- if [[ $(git add .github/badges/* --dry-run | wc -l) -gt 0 ]]; then
- git add .github/badges
- git commit -m "Update GitHub badges"
- git push origin HEAD
- else
- echo "Nothing to commit"
- fi
diff --git a/.github/actions/test-code/action.yml b/.github/actions/test-code/action.yml
deleted file mode 100644
index 0b784c5..0000000
--- a/.github/actions/test-code/action.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-# Should only be used in a job where MATLAB and MatBox is installed in previous steps
-
-name: 'Run toolbox test suites'
-description: 'Run the test suites available for a MATLAB toolbox'
-
-inputs:
- code_directory:
- description: 'Which folder to run the tests on'
- default: './code'
- tools_directory:
- description: 'Where the testToolbox function is located'
- default: './tools'
-
-runs:
- using: "composite"
- steps:
- - name: Run MATLAB test suites
- uses: matlab-actions/run-command@v2
- if: always()
- with:
- command: |
- addpath(genpath("${{ inputs.tools_directory }}"));
- if exist("testToolbox", "file")
- testToolbox();
- else
- matbox.tasks.testToolbox(pwd, ...
- "SourceFolderName", "${{ inputs.code_directory }}");
- end
-
- - name: Publish test results
- uses: EnricoMi/publish-unit-test-result-action@v2
- if: always()
- with:
- files: "docs/reports/test-results.xml"
diff --git a/.github/badges/code_issues.svg b/.github/badges/code_issues.svg
index 892f431..6071791 100644
--- a/.github/badges/code_issues.svg
+++ b/.github/badges/code_issues.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/.github/badges/tests.svg b/.github/badges/tests.svg
index b2979d5..b8630e0 100644
--- a/.github/badges/tests.svg
+++ b/.github/badges/tests.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/.github/workflows/reusable_check_code.yml b/.github/workflows/reusable_check_code.yml
deleted file mode 100644
index fbc4c19..0000000
--- a/.github/workflows/reusable_check_code.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-name: Analyse code
-
-on:
- workflow_call:
- inputs:
- code_directory:
- description: Path to the directory containing code. Code analysis will run on the contents of this folder and its subfolders.
- type: string
- default: 'code'
- tools_directory:
- description: Path to the directory containing CI tools. Used for locating customized MatBox tasks.
- type: string
- default: 'tools'
- matlab_release:
- description: MATLAB release to use when running code analysis.
- type: string
- default: 'latest'
-
-jobs:
- # This workflow contains a single job called "check"
- check:
- name: Check code
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out repo
- uses: actions/checkout@v4
-
- - name: Set up MATLAB (${{ inputs.matlab_release }})
- uses: matlab-actions/setup-matlab@v2
- with:
- release: ${{ inputs.matlab_release }}
- cache: true
-
- - name: Install MatBox
- uses: ehennestad/matbox/.github/actions/install-matbox@v0.9
-
- - name: Check code and upload report
- uses: ehennestad/matbox/.github/actions/check-code@v0.9
- with:
- code_directory: ${{ inputs.code_directory }}
- tools_directory: ${{ inputs.tools_directory }}
-
- - name: Commit SVG badges if updated
- if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
- uses: ehennestad/matbox/.github/actions/push-badges@v0.9
- with:
- pr-ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name }}
- pr-repo: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
diff --git a/.github/workflows/reusable_test_workflow.yml b/.github/workflows/reusable_test_workflow.yml
deleted file mode 100644
index 8107f3d..0000000
--- a/.github/workflows/reusable_test_workflow.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-name: Run tests
-
-on:
- workflow_call:
- inputs:
- code_directory:
- description: Path to the directory containing code. Code coverage and code analysis will run on the contents of this folder and its subfolders.
- type: string
- default: 'code'
- tools_directory:
- description: Path to the directory containing CI tools or tests. Used for locating unit tests and running customized MatBox tasks.
- type: string
- default: 'tools'
- matlab_release:
- description: MATLAB release to use for running test suites and code analysis.
- type: string
- default: 'latest'
- matlab_use_cache:
- description: Whether to cache the MATLAB installation for faster subsequent setups.
- type: boolean
- default: false
- matlab_products:
- description: Optional list of MATLAB products to install.
- type: string
- default: ''
-
- secrets:
- CODECOV_TOKEN:
- required: false
-
-jobs:
- # This workflow contains a single job called "test"
- test:
- name: Test toolbox code
- # The type of runner that the job will run on
- runs-on: ubuntu-latest
- env: # Assign secret to env to be able to use it in "if:" conditional below
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
-
- # Steps represent a sequence of tasks that will be executed as part of the job
- steps:
-
- - name: Check out repository
- uses: actions/checkout@v4
-
- - name: Set up MATLAB (${{ inputs.matlab_release }})
- uses: matlab-actions/setup-matlab@v2
- with:
- release: ${{ inputs.matlab_release }}
- cache: ${{ inputs.matlab_use_cache }}
- products: ${{ inputs.matlab_products }}
-
- - name: Install MatBox
- uses: ehennestad/matbox/.github/actions/install-matbox@v0.9
-
- - name: Check code and upload report
- uses: ehennestad/matbox/.github/actions/check-code@v0.9
- with:
- code_directory: ${{ inputs.code_directory }}
- tools_directory: ${{ inputs.tools_directory }}
-
- - name: Run tests
- uses: ehennestad/matbox/.github/actions/test-code@v0.9
- with:
- code_directory: ${{ inputs.code_directory }}
- tools_directory: ${{ inputs.tools_directory }}
-
- - name: Commit SVG badges if updated
- if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
- uses: ehennestad/matbox/.github/actions/push-badges@v0.9
- with:
- pr-ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name }}
- pr-repo: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
-
- - name: Upload code coverage report to Codecov
- uses: codecov/codecov-action@v5
- if: ${{ env.CODECOV_TOKEN != '' }}
- with:
- token: ${{ env.CODECOV_TOKEN }}
- files: docs/reports/codecoverage.xml
-
- - name: Save reports directory
- uses: actions/upload-artifact@v4
- if: always()
- with:
- name: reports
- path: docs/reports
diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
index cc4122c..a250cdd 100644
--- a/.github/workflows/run_tests.yml
+++ b/.github/workflows/run_tests.yml
@@ -27,8 +27,11 @@ concurrency:
jobs:
call-workflow-test-toolbox:
name: Test toolbox code
- uses: ehennestad/matbox/.github/workflows/reusable_test_workflow.yml@v0.9
+ uses: ehennestad/matbox-actions/.github/workflows/test-code-workflow.yml@v1
with:
+ source_directory: code
+ tests_directory: tools/tests
+ tools_directory: tools
matlab_use_cache: true
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/code/+matbox/+tasks/+internal/createBadge.m b/code/+matbox/+tasks/+internal/createBadge.m
new file mode 100644
index 0000000..60a1c01
--- /dev/null
+++ b/code/+matbox/+tasks/+internal/createBadge.m
@@ -0,0 +1,27 @@
+function createBadge(label, message, color, projectRootDirectory)
+% createBadge - Write a badge as JSON or as a legacy SVG file
+%
+% Writes a badge description as a JSON file (docs/reports/badges) when
+% the MATBOX_BADGE_FORMAT environment variable is set to "json". The
+% matbox-actions workflows set this variable and render the JSON files
+% to SVG badges with badge-maker.
+%
+% Otherwise falls back to rendering the SVG in MATLAB via the deprecated
+% pybadges Python package, for callers without a render step: local runs
+% and repositories pinned to older matbox-actions versions. This
+% fallback will be removed in a future major release.
+
+ arguments
+ label (1,1) string
+ message (1,1) string
+ color (1,1) string
+ projectRootDirectory (1,1) string {mustBeFolder}
+ end
+
+ if strcmpi(getenv("MATBOX_BADGE_FORMAT"), "json")
+ matbox.utility.writeBadgeJSONFile(label, message, color, ...
+ "OutputFolder", fullfile(projectRootDirectory, "docs", "reports", "badges"))
+ else
+ matbox.utility.createBadgeSvg(label, message, color, projectRootDirectory)
+ end
+end
diff --git a/code/+matbox/+tasks/codecheckToolbox.m b/code/+matbox/+tasks/codecheckToolbox.m
index 45d6f64..b81c753 100644
--- a/code/+matbox/+tasks/codecheckToolbox.m
+++ b/code/+matbox/+tasks/codecheckToolbox.m
@@ -92,7 +92,7 @@ function createCodeIssuesBadge(issueCount, projectRootDir)
color = "red";
end
- matbox.utility.createBadgeSvg("code issues", ...
+ matbox.tasks.internal.createBadge("code issues", ...
string(issueCount.Total), color, projectRootDir)
end
diff --git a/code/+matbox/+tasks/testToolbox.m b/code/+matbox/+tasks/testToolbox.m
index de11b1c..da15d6f 100644
--- a/code/+matbox/+tasks/testToolbox.m
+++ b/code/+matbox/+tasks/testToolbox.m
@@ -131,7 +131,7 @@ function createTestResultBadge(results, projectRootDirectory)
color = "red";
message = sprintf("%d/%d passed", numPassedTests, numTests);
end
- matbox.utility.createBadgeSvg("tests", message, color, projectRootDirectory)
+ matbox.tasks.internal.createBadge("tests", message, color, projectRootDirectory)
end
function displayTestResultSummary(testResults)
diff --git a/code/+matbox/+utility/createBadgeSvg.m b/code/+matbox/+utility/createBadgeSvg.m
index 82e0aa5..da0999b 100644
--- a/code/+matbox/+utility/createBadgeSvg.m
+++ b/code/+matbox/+utility/createBadgeSvg.m
@@ -1,4 +1,12 @@
function createBadgeSvg(label, message, color, projectRootDirectory, options)
+% createBadgeSvg - Create an SVG badge using the pybadges Python package
+%
+% Deprecated: when running via current matbox-actions workflows, MatBox
+% tasks write badge descriptions as JSON files instead (see
+% matbox.utility.writeBadgeJSONFile), which CI renders to SVG with
+% badge-maker. This function remains as a fallback for local runs and
+% older matbox-actions versions. It requires Python and the deprecated
+% pybadges package, and will be removed in a future major release.
arguments
label (1,1) string
diff --git a/tools/tasks/codecheckToolbox.m b/tools/tasks/codecheckToolbox.m
index f781459..c5819b5 100644
--- a/tools/tasks/codecheckToolbox.m
+++ b/tools/tasks/codecheckToolbox.m
@@ -1,5 +1,5 @@
-function codecheckToolbox()
+function codecheckToolbox(varargin)
installMatBox()
projectRootDir = matboxtools.projectdir();
- matbox.tasks.codecheckToolbox(projectRootDir)
+ matbox.tasks.codecheckToolbox(projectRootDir, varargin{:})
end
diff --git a/tools/tests/+matboxtools/+unittest/TasksTest.m b/tools/tests/+matboxtools/+unittest/TasksTest.m
index 40073a1..9ea5c36 100644
--- a/tools/tests/+matboxtools/+unittest/TasksTest.m
+++ b/tools/tests/+matboxtools/+unittest/TasksTest.m
@@ -34,6 +34,29 @@ function testCodecheckToolbox(testCase)
testCase.verifyTrue(isfolder(fullfile(pwd, "docs", "reports")))
end
+ function testCodecheckToolboxCreatesBadgeJson(testCase)
+ pathStr = matboxtools.projectdir();
+ copyfile(pathStr, pwd);
+
+ % The matbox-actions workflows set this environment variable to
+ % request badge JSON instead of legacy in-MATLAB SVG rendering.
+ previousValue = getenv("MATBOX_BADGE_FORMAT");
+ setenv("MATBOX_BADGE_FORMAT", "json")
+ testCase.addTeardown(@() setenv("MATBOX_BADGE_FORMAT", previousValue))
+
+ matbox.tasks.codecheckToolbox(pwd, ...
+ "CreateBadge", true, "SaveReport", false);
+
+ badgeFile = fullfile(pwd, "docs", "reports", "badges", "code_issues.json");
+ testCase.verifyTrue(isfile(badgeFile), ...
+ "Expected badge JSON file was not created.")
+
+ badgeInfo = jsondecode(fileread(badgeFile));
+ testCase.verifyEqual(badgeInfo.label, 'code issues')
+ testCase.verifyTrue(ismember(string(badgeInfo.color), ...
+ ["green", "yellow", "red"]))
+ end
+
function testPackageToolbox(testCase)
pathStr = matboxtools.projectdir();
copyfile(pathStr, pwd);