Skip to content
This repository was archived by the owner on Mar 27, 2025. It is now read-only.

Commit ddf6253

Browse files
committed
Add Support for sourceFolder option in FreeStyle projects
1 parent 6a2ca2e commit ddf6253

File tree

9 files changed

+301
-29
lines changed

9 files changed

+301
-29
lines changed

src/main/java/com/mathworks/ci/RunMatlabTestsBuilder.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,12 @@
1111
import java.io.IOException;
1212
import java.util.*;
1313
import javax.annotation.Nonnull;
14+
import hudson.*;
15+
import hudson.model.*;
1416
import org.kohsuke.stapler.DataBoundConstructor;
1517
import org.kohsuke.stapler.DataBoundSetter;
1618
import org.kohsuke.stapler.StaplerRequest;
17-
import hudson.EnvVars;
18-
import hudson.Extension;
19-
import hudson.FilePath;
20-
import hudson.Launcher;
2119
import hudson.Launcher.ProcStarter;
22-
import hudson.model.AbstractProject;
23-
import hudson.model.Result;
24-
import hudson.model.Run;
25-
import hudson.model.TaskListener;
2620
import hudson.tasks.BuildStepDescriptor;
2721
import hudson.tasks.Builder;
2822
import jenkins.tasks.SimpleBuildStep;
@@ -47,16 +41,15 @@ public class RunMatlabTestsBuilder extends Builder implements SimpleBuildStep, M
4741
private Artifact stmResultsArtifact = new NullArtifact();
4842
private Artifact modelCoverageArtifact = new NullArtifact();
4943
private Artifact pdfReportArtifact = new NullArtifact();
50-
44+
private SourceFolder sourceFolder;
45+
5146
@DataBoundConstructor
5247
public RunMatlabTestsBuilder() {
5348

5449
}
5550

56-
5751
// Getter and Setters to access local members
5852

59-
6053
@DataBoundSetter
6154
public void setTapArtifact(TapArtifact tapArtifact) {
6255
this.tapArtifact = tapArtifact;
@@ -86,7 +79,13 @@ public void setModelCoverageArtifact(ModelCovArtifact modelCoverageArtifact) {
8679
public void setPdfReportArtifact(PdfArtifact pdfReportArtifact) {
8780
this.pdfReportArtifact = pdfReportArtifact;
8881
}
89-
82+
83+
@DataBoundSetter
84+
public void setSourceFolder(SourceFolder sourceFolder) {
85+
this.sourceFolder = sourceFolder;
86+
}
87+
88+
9089
public String getTapReportFilePath() {
9190
return this.getTapArtifact().getFilePath();
9291
}
@@ -135,6 +134,10 @@ public String getPdfReportFilePath() {
135134
return this.getPdfReportArtifact().getFilePath();
136135
}
137136

137+
public SourceFolder getSourceFolder() {
138+
return this.sourceFolder;
139+
}
140+
138141
private Artifact getArtifactObject(boolean isChecked, Artifact returnVal) {
139142
// If previously checked assign valid artifact object else NullArtifact.
140143
return (isChecked) ? returnVal : new NullArtifact();
@@ -284,6 +287,12 @@ private String getInputArguments() {
284287
artifact.addFilePathArgTo(args);
285288
}
286289

290+
// Add source folder options to argument
291+
SourceFolder sf = getSourceFolder();
292+
if(sf != null && sf.getSourceFolderPaths().size() != 0){
293+
sf.addFilePathArgTo(args);
294+
}
295+
287296
args.forEach((key, val) -> inputArgsList.add("'" + key + "'" + "," + "'" + val + "'"));
288297

289298
return String.join(",", inputArgsList);
@@ -300,6 +309,7 @@ private String getInputArguments() {
300309
* 7Csort:date/jenkinsci-dev/AFYHSG3NUEI/UsVJIKoE4B8J
301310
*
302311
*/
312+
303313
public static class PdfArtifact extends AbstractArtifactImpl {
304314

305315
private static final String PDF_TEST_REPORT = "PDFTestReport";

src/main/java/com/mathworks/ci/RunMatlabTestsStep.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,10 @@ private Map<String, String> getGenscriptArgs() {
153153
args.put("SimulinkTestResults", getTestResultsSimulinkTest());
154154
args.put("CoberturaCodeCoverage", getCodeCoverageCobertura());
155155
args.put("CoberturaModelCoverage", getModelCoverageCobertura());
156-
157-
String sourceStr = String.join(";", getSourceFolder());
158-
args.put("SourceFolder", sourceStr);
156+
if(getSourceFolder() != null && getSourceFolder().size() != 0){
157+
String sourceStr = String.join(";", getSourceFolder());
158+
args.put("SourceFolder", sourceStr);
159+
}
159160

160161
return args;
161162
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.mathworks.ci;
2+
3+
/**
4+
* Copyright 2019-2020 The MathWorks, Inc.
5+
*
6+
* Describable class for Source Folder Option in RunMATLABTest Build step.
7+
*
8+
*/
9+
10+
import hudson.Extension;
11+
import hudson.Util;
12+
import hudson.model.AbstractDescribableImpl;
13+
import hudson.model.Descriptor;
14+
import org.kohsuke.stapler.DataBoundConstructor;
15+
import org.kohsuke.stapler.DataBoundSetter;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.stream.Collectors;
20+
21+
public class SourceFolder extends AbstractDescribableImpl<SourceFolder> {
22+
23+
private List<SourceFolderPaths> sourceFolderPaths = new ArrayList<>();
24+
private transient final String SOURCE_FOLDER = "SourceFolder";
25+
26+
@DataBoundConstructor
27+
public SourceFolder() {
28+
29+
}
30+
31+
@DataBoundSetter
32+
public void setSourceFolderPaths(List<SourceFolderPaths> sourceFolderPaths) {
33+
this.sourceFolderPaths = Util.fixNull(sourceFolderPaths);
34+
}
35+
36+
public List<SourceFolderPaths> getSourceFolderPaths() {
37+
return this.sourceFolderPaths;
38+
}
39+
40+
public void addFilePathArgTo(Map<String, String> inputArgs) {
41+
// Concatenate all source folders to a single ";" separated string
42+
inputArgs.put(SOURCE_FOLDER, this.sourceFolderPaths.stream()
43+
.map(SourceFolderPaths::getSrcFolderPath)
44+
.collect(Collectors.joining(";")));
45+
}
46+
47+
@Extension public static class DescriptorImpl extends Descriptor<SourceFolder> {
48+
@Override
49+
public String getDisplayName() {
50+
return "";
51+
}
52+
}
53+
54+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.mathworks.ci;
2+
3+
/**
4+
* Copyright 2019-2020 The MathWorks, Inc.
5+
*
6+
* Describable class for Repeatable Source Folder text boxes in Source Folder option
7+
* in RunMATLABTest Build step.
8+
*
9+
*/
10+
11+
import hudson.Extension;
12+
import hudson.model.AbstractDescribableImpl;
13+
import hudson.model.Descriptor;
14+
import org.kohsuke.stapler.DataBoundConstructor;
15+
16+
public class SourceFolderPaths extends AbstractDescribableImpl<SourceFolderPaths> {
17+
18+
private String srcFolderPath;
19+
20+
@DataBoundConstructor
21+
public SourceFolderPaths(String srcFolderPath){
22+
this.srcFolderPath = srcFolderPath;
23+
}
24+
25+
public String getSrcFolderPath() {
26+
return this.srcFolderPath;
27+
}
28+
29+
@Extension
30+
public static final class DescriptorImpl extends Descriptor<SourceFolderPaths> {
31+
32+
@Override
33+
public String getDisplayName() {
34+
return "";
35+
}
36+
}
37+
}

src/main/resources/com/mathworks/ci/RunMatlabTestsBuilder/config.jelly

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
<?jelly escape-by-default='true'?>
22
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
3-
4-
<f:section title="Generate Test Artifacts">
3+
4+
<f:block>
5+
<br></br>
6+
<f:optionalProperty field="sourceFolder" title="Source Folder" />
7+
</f:block>
8+
9+
<f:block>
10+
<br></br>
11+
<b>Generate Test Artifacts</b>
512
<f:optionalBlock name="pdfReportArtifact" field="pdfReportArtifact" title="PDF test report" checked="${instance.pdfReportArtifact.selected}">
613
<f:entry field="pdfReportFilePath" title="File path: ">
714
<f:textbox default="matlabTestArtifacts/testreport.pdf"/>
@@ -26,9 +33,11 @@
2633
</f:entry>
2734
</f:optionalBlock>
2835

29-
</f:section>
36+
</f:block>
3037

31-
<f:section title="Generate Coverage Artifacts">
38+
<f:block>
39+
<br></br>
40+
<b>Generate Coverage Artifacts</b>
3241
<f:optionalBlock name="coberturaArtifact" field="coberturaArtifact" title="Cobertura code coverage" checked="${instance.coberturaArtifact.selected}">
3342
<f:entry field="coberturaReportFilePath" title="File path: ">
3443
<f:textbox default="matlabTestArtifacts/cobertura.xml"/>
@@ -40,5 +49,5 @@
4049
<f:textbox default="matlabTestArtifacts/coberturamodelcoverage.xml"/>
4150
</f:entry>
4251
</f:optionalBlock>
43-
</f:section>
44-
</j:jelly>
52+
</f:block>
53+
</j:jelly>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div>
2+
<p>Optionally specify the location of the folder containing source code, relative to the project root folder. The specified folder and its subfolders are added to the top of the MATLAB search path. To generate a code coverage report, MATLAB uses only the source code in the specified folder and its subfolders. </p>
3+
<p>Specify a source folder path in the input box. Click on 'Add folder' to add more values.</p>
4+
</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?jelly escape-by-default='true'?>
2+
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
3+
<f:entry title="Folder path:">
4+
<f:repeatable minimum="1" field="sourceFolderPaths" noAddButton="true">
5+
<table width="100%">
6+
<f:textbox field="srcFolderPath"/>
7+
<div align ="right">
8+
<input type="button" value="Add folder" class="repeatable-add show-if-last" />
9+
<input type="button" value="Delete" class="repeatable-delete show-if-not-only" />
10+
</div>
11+
</table>
12+
</f:repeatable>
13+
</f:entry>
14+
</j:jelly>
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.mathworks.ci;
2+
/**
3+
* Copyright 2019-2020 The MathWorks, Inc.
4+
*
5+
* Test class for RunMatlabTestsBuilder Persistence
6+
*
7+
*/
8+
import hudson.model.FreeStyleProject;
9+
import hudson.model.Item;
10+
import org.junit.*;
11+
import org.jvnet.hudson.test.RestartableJenkinsRule;
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import java.util.stream.Collectors;
15+
16+
import static org.junit.Assert.*;
17+
18+
public class RunMatlabTestBuilderPersistenceTest {
19+
private final String tapFilePath = "mytap/report.tap";
20+
private final String pdfFilePath = "mypdf/report.pdf";
21+
private final String jUnitFilePath = "myjunit/report.xml";
22+
private final String coberturaFilePath = "mycobertura/report.xml";
23+
private final String modelCovFilePath = "mymodel/report.xml";
24+
private final String stmFilePath = "mystm/results.mldatx";
25+
private final List<SourceFolderPaths> paths = new ArrayList<>();
26+
27+
@Rule
28+
public RestartableJenkinsRule jenkins = new RestartableJenkinsRule();
29+
30+
private boolean areSourcePathsEqual(List<SourceFolderPaths> listA, List<SourceFolderPaths> listB) {
31+
return listA.stream()
32+
.map(SourceFolderPaths::getSrcFolderPath)
33+
.collect(Collectors.toList())
34+
.equals(listB.stream()
35+
.map(SourceFolderPaths::getSrcFolderPath)
36+
.collect(Collectors.toList()));
37+
}
38+
39+
/*
40+
* Test to verify artifacts are correctly restored after Jenkins restarts.
41+
* */
42+
43+
@Test
44+
public void verifyArtifactSpecPersistAfterRestart() {
45+
jenkins.then(r -> {
46+
FreeStyleProject project = r.createFreeStyleProject();
47+
RunMatlabTestsBuilder testBuilder = new RunMatlabTestsBuilder();
48+
49+
RunMatlabTestsBuilder.TapArtifact tap = new RunMatlabTestsBuilder.TapArtifact(tapFilePath);
50+
RunMatlabTestsBuilder.PdfArtifact pdf = new RunMatlabTestsBuilder.PdfArtifact(pdfFilePath);
51+
RunMatlabTestsBuilder.JunitArtifact junit = new RunMatlabTestsBuilder.JunitArtifact(jUnitFilePath);
52+
RunMatlabTestsBuilder.CoberturaArtifact cobertura = new RunMatlabTestsBuilder.CoberturaArtifact(coberturaFilePath);
53+
RunMatlabTestsBuilder.ModelCovArtifact modelCov = new RunMatlabTestsBuilder.ModelCovArtifact(modelCovFilePath);
54+
RunMatlabTestsBuilder.StmResultsArtifact stmResults = new RunMatlabTestsBuilder.StmResultsArtifact(stmFilePath);
55+
56+
testBuilder.setTapArtifact(tap);
57+
testBuilder.setPdfReportArtifact(pdf);
58+
testBuilder.setJunitArtifact(junit);
59+
testBuilder.setCoberturaArtifact(cobertura);
60+
testBuilder.setModelCoverageArtifact(modelCov);
61+
testBuilder.setStmResultsArtifact(stmResults);
62+
63+
project.getBuildersList().add(testBuilder);
64+
project.save();
65+
});
66+
67+
jenkins.then(r -> {
68+
// Make sure there's only one project
69+
List<Item> items = r.getInstance().getAllItems();
70+
assertEquals(items.size(), 1);
71+
72+
FreeStyleProject p = (FreeStyleProject) items.get(0);
73+
RunMatlabTestsBuilder savedInstance = p.getBuildersList().get(RunMatlabTestsBuilder.class);
74+
75+
// Verify artifacts are not NullArtifact instances and verify saved path values
76+
assertTrue(savedInstance.getTapArtifact() instanceof RunMatlabTestsBuilder.TapArtifact);
77+
assertTrue(savedInstance.getPdfReportArtifact() instanceof RunMatlabTestsBuilder.PdfArtifact);
78+
assertTrue(savedInstance.getJunitArtifact() instanceof RunMatlabTestsBuilder.JunitArtifact);
79+
assertTrue(savedInstance.getCoberturaArtifact() instanceof RunMatlabTestsBuilder.CoberturaArtifact);
80+
assertTrue(savedInstance.getModelCoverageArtifact() instanceof RunMatlabTestsBuilder.ModelCovArtifact);
81+
assertTrue(savedInstance.getStmResultsArtifact() instanceof RunMatlabTestsBuilder.StmResultsArtifact);
82+
83+
assertEquals(savedInstance.getTapReportFilePath(), tapFilePath);
84+
assertEquals(savedInstance.getPdfReportFilePath(), pdfFilePath);
85+
assertEquals(savedInstance.getJunitReportFilePath(), jUnitFilePath);
86+
assertEquals(savedInstance.getCoberturaReportFilePath(), coberturaFilePath);
87+
assertEquals(savedInstance.getModelCoverageFilePath(), modelCovFilePath);
88+
assertEquals(savedInstance.getStmResultsFilePath(), stmFilePath);
89+
});
90+
}
91+
92+
/*
93+
* Test to verify Source Folder specification is correctly restored after Jenkins restarts
94+
* */
95+
96+
@Test
97+
public void verifySourceFolderSpecPersistence() {
98+
jenkins.then(r -> {
99+
paths.add(new SourceFolderPaths("src/A"));
100+
paths.add(new SourceFolderPaths("src/B"));
101+
102+
FreeStyleProject project = r.createFreeStyleProject();
103+
RunMatlabTestsBuilder testBuilder = new RunMatlabTestsBuilder();
104+
SourceFolder sf = new SourceFolder();
105+
sf.setSourceFolderPaths(paths);
106+
testBuilder.setSourceFolder(sf);
107+
project.getBuildersList().add(testBuilder);
108+
project.save();
109+
});
110+
111+
jenkins.then(r -> {
112+
// Make sure there's only one project
113+
List<Item> items = r.getInstance().getAllItems();
114+
assertEquals(items.size(), 1);
115+
116+
FreeStyleProject project = (FreeStyleProject) items.get(0);
117+
// Compare sourceFolder values
118+
RunMatlabTestsBuilder saveInstance = project.getBuildersList().get(RunMatlabTestsBuilder.class);
119+
assertNotNull(saveInstance.getSourceFolder());
120+
List<SourceFolderPaths> savedList = saveInstance.getSourceFolder().getSourceFolderPaths();
121+
122+
assertTrue(areSourcePathsEqual(paths, savedList));
123+
});
124+
}
125+
}

0 commit comments

Comments
 (0)