Skip to content

Commit 4208c95

Browse files
authored
Merge pull request #2432 from farid-zare/developPlus
Develop plus
2 parents 8b7ea83 + 05806df commit 4208c95

File tree

4 files changed

+177
-117
lines changed

4 files changed

+177
-117
lines changed

.github/workflows/cobratoolboxCI.yml

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: cobratoolboxCI (merge, test, and upload)
2+
on:
3+
pull_request:
4+
types: [opened, synchronize, reopened]
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
build:
12+
runs-on: self-hosted
13+
steps:
14+
- name: Check out merged PR code
15+
uses: actions/checkout@v4
16+
17+
- name: Run MATLAB Tests
18+
run: |
19+
matlab -batch "run('initCobraToolbox.m'); run('test/testAll.m');"
20+
21+
- name: Convert JUnit to CTRF
22+
run: |
23+
npx junit-to-ctrf ./testReport.junit.xml -o ./ctrf/ctrf-report.json
24+
25+
- name: Upload CTRF Artifact
26+
uses: actions/upload-artifact@v4
27+
with:
28+
name: testReport
29+
path: ./ctrf/ctrf-report.json
30+
31+
- name: Save PR Number
32+
run: echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
33+
34+
- name: Upload PR Number as Artifact
35+
run: echo $PR_NUMBER > pr_number.txt
36+
shell: bash
37+
38+
- name: Upload PR Number Artifact
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: pr_number
42+
path: pr_number.txt
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: testReport (Comment on PR)
2+
3+
on:
4+
workflow_run:
5+
workflows: ['cobratoolboxCI (merge, test, and upload)']
6+
types: [completed]
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
publish-report:
14+
runs-on: ubuntu-latest
15+
if: github.event.workflow_run.conclusion == 'success'
16+
steps:
17+
18+
- name: Download CTRF Artifact
19+
uses: dawidd6/action-download-artifact@v8
20+
with:
21+
name: testReport
22+
run_id: ${{ github.event.workflow_run.id }}
23+
path: artifacts
24+
25+
- name: Download PR Number Artifact
26+
uses: dawidd6/action-download-artifact@v8
27+
with:
28+
name: pr_number
29+
run_id: ${{ github.event.workflow_run.id }}
30+
path: pr_number
31+
32+
- name: Read PR Number
33+
id: read_pr_number
34+
run: |
35+
PR_NUMBER=$(cat pr_number/pr_number.txt)
36+
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
37+
38+
- name: Publish Test Report
39+
uses: ctrf-io/[email protected]
40+
with:
41+
report-path: 'artifacts/ctrf-report.json'
42+
summary-report: true
43+
failed-report: true
44+
issue: ${{ env.PR_NUMBER }}
45+
env:
46+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

test/testAll.m

Lines changed: 89 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@
1313
fprintf([' \\_____| \\_____/ |_____/ |_| \\_\\ |_| |_| |\n']);
1414
fprintf(' | \n\n');
1515

16+
% Define CI boolean
17+
CIenv = false;
18+
1619
% request explicitly from the user to launch test suite locally
17-
% if contains(getenv('HOME'), 'vmhadmin') || contains(getenv('HOME'), 'jenkins')
1820
if contains(getenv('HOME'), 'saleh')
1921
% Running in CI environment
20-
% fprintf('Running test in Jenkins/CI environment\n');
21-
fprintf('Running test in cobratoolbox/CI environment\n');
22-
22+
fprintf('Running test in cobratoolbox/CI environment\n');
23+
24+
% Set CI boolean to true
25+
CIenv = true;
26+
2327
% on the CI, always reset the path to make absolutely sure, that we test
2428
% the current version
2529
restoredefaultpath;
@@ -29,7 +33,7 @@
2933
while isempty(reply)
3034
reply = input([' -> Do you want to launch the test suite locally? Time estimate: more than 60 minutes Y/N: '], 's');
3135
end
32-
36+
3337
if strcmpi(reply, 'y') || strcmpi(reply, 'yes')
3438
launchTestSuite = true;
3539
else
@@ -74,7 +78,7 @@
7478
testDirContent = getFilesInDir('type', 'all'); % Get all currently present files in the folder.
7579
testDirPath = pwd;
7680
cd(currentDir);
77-
%{
81+
%{
7882
if ~isempty(strfind(getenv('HOME'), 'jenkins')) || ~isempty(strfind(getenv('USERPROFILE'), 'jenkins'))
7983
WAITBAR_TYPE = 0;
8084
@@ -86,7 +90,7 @@
8690
else
8791
WAITBAR_TYPE = 1;
8892
end
89-
%}
93+
%}
9094
if verLessThan('matlab', '8.2')
9195
error('The testsuite of The COBRA Toolbox can only be run with MATLAB R2014b+.')
9296
end
@@ -102,7 +106,7 @@
102106
% only retain the lines that end with .txt and .m and
103107
% are not comments and point to files in the /src folder
104108
ignoredPatterns = {'^.{0,3}$', ... % Is smaller than four.
105-
['^[^s][^r][^c][^' regexptranslate('escape', filesep) ']']}; % does not start with src/
109+
['^[^s][^r][^c][^' regexptranslate('escape', filesep) ']']}; % does not start with src/
106110
filterPatterns = {'\.txt$', '\.m$'}; % Is either a .m file or a .txt file.
107111
ignoreFiles = getIgnoredFiles(ignoredPatterns, filterPatterns);
108112

@@ -122,10 +126,10 @@
122126
while ~feof(fid)
123127
lineOfFile = strtrim(char(fgetl(fid)));
124128
if length(lineOfFile) > 0 && length(strfind(lineOfFile(1), '%')) ~= 1 ...
125-
&& length(strfind(lineOfFile, 'end')) ~= 1 && length(strfind(lineOfFile, 'otherwise')) ~= 1 ...
126-
&& length(strfind(lineOfFile, 'switch')) ~= 1 && length(strfind(lineOfFile, 'else')) ~= 1 ...
127-
&& length(strfind(lineOfFile, 'case')) ~= 1 && length(strfind(lineOfFile, 'function')) ~= 1
128-
nCodeLines = nCodeLines + 1;
129+
&& length(strfind(lineOfFile, 'end')) ~= 1 && length(strfind(lineOfFile, 'otherwise')) ~= 1 ...
130+
&& length(strfind(lineOfFile, 'switch')) ~= 1 && length(strfind(lineOfFile, 'else')) ~= 1 ...
131+
&& length(strfind(lineOfFile, 'case')) ~= 1 && length(strfind(lineOfFile, 'function')) ~= 1
132+
nCodeLines = nCodeLines + 1;
129133

130134
elseif length(lineOfFile) == 0
131135
nEmptyLines = nEmptyLines + 1;
@@ -142,11 +146,11 @@
142146

143147
grades = {'A', 'B', 'C', 'D', 'E', 'F'};
144148
intervals = [0, 3;
145-
3, 6;
146-
6, 9;
147-
9, 12;
148-
12, 15;
149-
15, 100];
149+
3, 6;
150+
6, 9;
151+
9, 12;
152+
12, 15;
153+
15, 100];
150154

151155
grade = 'F';
152156
for i = 1:length(intervals)
@@ -182,75 +186,78 @@
182186
sumFailed = sum(resultTable.Failed);
183187

184188
fprintf(['\n > ', num2str(sumFailed), ' tests failed. ', num2str(sumSkipped), ' tests were skipped due to missing requirements.\n\n']);
185-
%% NEW: Generate JUnit XML report for Codecov
186-
187-
xmlFileName = 'testReport.junit.xml';
188189

189-
fid = fopen(xmlFileName, 'w');
190-
if fid == -1
191-
error('Could not open file for writing: %s', xmlFileName);
192-
end
190+
if CIenv
191+
%% NEW: Generate JUnit XML report for Codecov
193192

194-
fprintf(fid, '<?xml version="1.0" encoding="UTF-8"?>\n');
193+
xmlFileName = 'testReport.junit.xml';
195194

196-
numTests = height(resultTable);
197-
numFailures = sum(resultTable.Failed);
198-
numErrors = sum(resultTable.Failed);
199-
numSkipped = sum(resultTable.Skipped);
195+
fid = fopen(xmlFileName, 'w');
196+
if fid == -1
197+
error('Could not open file for writing: %s', xmlFileName);
198+
end
200199

201-
% Compute total time and also count how many are "failures" vs. "errors"
202-
totalTime = sum(resultTable.Time);
200+
fprintf(fid, '<?xml version="1.0" encoding="UTF-8"?>\n');
203201

204-
% 1) Wrap in <testsuites> -- typical JUnit format
205-
fprintf(fid, '<testsuites name="COBRA Toolbox Test Suites" tests="%d" failures="%d" errors="%d" time="%.3f">\n', ...
206-
numTests, numFailures, numErrors, totalTime);
202+
numTests = height(resultTable);
203+
numFailures = sum(resultTable.Failed);
204+
numErrors = sum(resultTable.Failed);
205+
numSkipped = sum(resultTable.Skipped);
207206

208-
% 2) A single <testsuite> inside
209-
fprintf(fid, ' <testsuite name="COBRA Toolbox Test Suite" tests="%d" failures="%d" errors="%d" skipped="%d" time="%.3f">\n', ...
210-
numTests, numFailures, numErrors, numSkipped, totalTime);
207+
% Compute total time and also count how many are "failures" vs. "errors"
208+
totalTime = sum(resultTable.Time);
211209

212-
% 3) Loop over each test case
213-
for i = 1:numTests
214-
testName = resultTable.TestName{i};
215-
if isnan(resultTable.Time(i))
216-
tVal = 0;
217-
else
218-
tVal = resultTable.Time(i);
219-
end
210+
% 1) Wrap in <testsuites> -- typical JUnit format
211+
fprintf(fid, '<testsuites name="COBRA Toolbox Test Suites" tests="%d" failures="%d" errors="%d" time="%.3f">\n', ...
212+
numTests, numFailures, numErrors, totalTime);
220213

221-
% Start the <testcase> tag
222-
fprintf(fid, ' <testcase classname="COBRA Toolbox" name="%s" time="%.3f"', testName, tVal);
223-
224-
if resultTable.Passed(i)
225-
% Passed => just close
226-
fprintf(fid, '/>\n');
227-
elseif resultTable.Skipped(i)
228-
% Skipped => <skipped/>
229-
fprintf(fid, '>\n');
230-
fprintf(fid, ' <skipped message="%s"/>\n', escapeXML(resultTable.Details{i}));
231-
fprintf(fid, ' </testcase>\n');
232-
else
233-
% Not passed, not skipped => either <failure> or <error>
234-
% Check the .Error or .Details to decide
235-
errMsg = result(i).Error.message; % or getReport()
236-
237-
% Heuristic: if "Assertion" => <failure>, else <error>.
238-
if contains(errMsg, 'Assertion') || contains(errMsg, 'assert')
239-
fprintf(fid, '>\n');
240-
fprintf(fid, ' <failure message="%s"/>\n', escapeXML(errMsg));
214+
% 2) A single <testsuite> inside
215+
fprintf(fid, ' <testsuite name="COBRA Toolbox Test Suite" tests="%d" failures="%d" errors="%d" skipped="%d" time="%.3f">\n', ...
216+
numTests, numFailures, numErrors, numSkipped, totalTime);
217+
218+
% 3) Loop over each test case
219+
for i = 1:numTests
220+
testName = resultTable.TestName{i};
221+
if isnan(resultTable.Time(i))
222+
tVal = 0;
241223
else
242-
fprintf(fid, '>\n');
243-
fprintf(fid, ' <error message="%s"/>\n', escapeXML(errMsg));
224+
tVal = resultTable.Time(i);
244225
end
245226

246-
fprintf(fid, ' </testcase>\n');
227+
% Start the <testcase> tag
228+
fprintf(fid, ' <testcase name="%s" time="%.3f"', testName, tVal);
229+
230+
if resultTable.Passed(i)
231+
% Passed => just close
232+
fprintf(fid, '/>\n');
233+
elseif resultTable.Skipped(i)
234+
% Skipped => <skipped/>
235+
fprintf(fid, '>\n');
236+
fprintf(fid, ' <skipped message="%s"/>\n', escapeXML(resultTable.Details{i}));
237+
fprintf(fid, ' </testcase>\n');
238+
else
239+
% Not passed, not skipped => either <failure> or <error>
240+
% Check the .Error or .Details to decide
241+
errMsg = result(i).Error.message; % or getReport()
242+
243+
% Heuristic: if "Assertion" => <failure>, else <error>.
244+
if contains(errMsg, 'Assertion') || contains(errMsg, 'assert')
245+
fprintf(fid, '>\n');
246+
fprintf(fid, ' <failure message="%s"/>\n', escapeXML(errMsg));
247+
else
248+
fprintf(fid, '>\n');
249+
fprintf(fid, ' <error message="%s"/>\n', escapeXML(errMsg));
250+
end
251+
252+
fprintf(fid, ' </testcase>\n');
253+
end
247254
end
248-
end
249255

250-
% Close out the suite and suites
251-
fprintf(fid, ' </testsuite>\n');
252-
fprintf(fid, '</testsuites>\n');
253-
fclose(fid);
256+
% Close out the suite and suites
257+
fprintf(fid, ' </testsuite>\n');
258+
fprintf(fid, '</testsuites>\n');
259+
fclose(fid);
260+
end
254261
%% End of XML generation
255262

256263
% count the number of covered lines of code
@@ -364,13 +371,13 @@
364371

365372
%% Local helper function to escape XML special characters.
366373
function out = escapeXML(in)
367-
if isempty(in)
368-
out = '';
369-
return;
370-
end
371-
out = strrep(in, '&', '&amp;');
372-
out = strrep(out, '<', '&lt;');
373-
out = strrep(out, '>', '&gt;');
374-
out = strrep(out, '"', '&quot;');
375-
out = strrep(out, '''', '&apos;');
374+
if isempty(in)
375+
out = '';
376+
return;
377+
end
378+
out = strrep(in, '&', '&amp;');
379+
out = strrep(out, '<', '&lt;');
380+
out = strrep(out, '>', '&gt;');
381+
out = strrep(out, '"', '&quot;');
382+
out = strrep(out, '''', '&apos;');
376383
end

0 commit comments

Comments
 (0)