Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/main/java/hudson/plugins/robot/RobotBuildAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class RobotBuildAction extends AbstractTestResultAction<RobotBuildAction>
private String xAxisLabel;

private boolean countSkippedTests;
private boolean useArtifactManager;

static {
XSTREAM.alias("result",RobotResult.class);
Expand All @@ -85,7 +86,7 @@ public class RobotBuildAction extends AbstractTestResultAction<RobotBuildAction>
*/
public RobotBuildAction(Run<?, ?> build, RobotResult result,
String outputPath, TaskListener listener, String logFileLink, String logHtmlLink, boolean enableCache, String xAxisLabel,
boolean countSkippedTests) {
boolean countSkippedTests, boolean useArtifactManager) {
super();
super.onAttached(build);
this.build = build;
Expand All @@ -95,6 +96,7 @@ public RobotBuildAction(Run<?, ?> build, RobotResult result,
this.enableCache = enableCache;
this.xAxisLabel = xAxisLabel;
this.countSkippedTests = countSkippedTests;
this.useArtifactManager = useArtifactManager;
setResult(result, listener);
}

Expand Down Expand Up @@ -332,6 +334,10 @@ public String getUrlName() {
return "robot";
}

public String getReportUrlName() {
return getUseArtifactManager() ? "artifact/" : getUrlName() + "/report/";
}

public List<RobotCaseResult> getAllTests() {
return getResult().getAllCases();
}
Expand All @@ -343,4 +349,8 @@ public boolean isCountSkippedTests() {
public void setCountSkippedTests(boolean countSkippedTests) {
this.countSkippedTests = countSkippedTests;
}

public boolean getUseArtifactManager() {
return useArtifactManager;
}
}
105 changes: 95 additions & 10 deletions src/main/java/hudson/plugins/robot/RobotPublisher.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@
import java.io.PrintStream;
import java.io.Serial;
import java.io.Serializable;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import jakarta.servlet.ServletException;

Expand All @@ -47,6 +51,8 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import jenkins.model.ArtifactManager;

public class RobotPublisher extends Recorder implements Serializable,
MatrixAggregatable, SimpleBuildStep {

Expand All @@ -71,6 +77,7 @@
private String[] otherFiles;
final private String overwriteXAxisLabel;
final private boolean enableCache;
final private boolean useArtifactManager;

//Default to true
private boolean countSkippedTests = false;
Expand All @@ -88,12 +95,13 @@
* @param unstableThreshold Threshold of test pass percentage for unstable builds
* @param otherFiles Other files to be saved
* @param enableCache True if caching is used
* @param useArtifactManager True if Artifact Manager is used
*/
@DataBoundConstructor
public RobotPublisher(String archiveDirName, String outputPath, String outputFileName,
boolean disableArchiveOutput, String reportFileName, String logFileName,
double passThreshold, double unstableThreshold,
boolean countSkippedTests, String otherFiles, boolean enableCache, String overwriteXAxisLabel) {
boolean countSkippedTests, String otherFiles, boolean enableCache, String overwriteXAxisLabel, boolean useArtifactManager) {
this.archiveDirName = archiveDirName;
this.outputPath = outputPath;
this.outputFileName = outputFileName;
Expand All @@ -105,6 +113,7 @@
this.countSkippedTests = countSkippedTests;
this.enableCache = enableCache;
this.overwriteXAxisLabel = overwriteXAxisLabel;
this.useArtifactManager = useArtifactManager;

if (otherFiles != null) {
String[] filemasks = otherFiles.split(",");
Expand Down Expand Up @@ -235,6 +244,15 @@
return overwriteXAxisLabel;
}

/**
* Gets value of useArtifactManager
*
* @return true if Artifact Manager is used
*/
public boolean getUseArtifactManager() {
return useArtifactManager;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -286,25 +304,26 @@

if (!DEFAULT_JENKINS_ARCHIVE_DIR.equalsIgnoreCase(getArchiveDirName())) {
logger.println(Messages.robot_publisher_copying());
//Save configured Robot files (including split output) to build dir
copyFilesToBuildDir(build, workspace, expandedOutputPath, StringUtils.join(modifyMasksforSplittedOutput(new String[]{expandedReportFileName, expandedLogFileName, logFileJavascripts}), ","));
//Save configured Robot files (including split output) to destination dir
copyFilesToDestination(build, workspace, expandedOutputPath, StringUtils.join(modifyMasksforSplittedOutput(new String[]{expandedReportFileName, expandedLogFileName, logFileJavascripts}), ","), launcher, listener);

if (!getDisableArchiveOutput()) {
copyFilesToBuildDir(build, workspace, expandedOutputPath, StringUtils.join(modifyMasksforSplittedOutput(new String[]{expandedOutputFileName}), ","));
copyFilesToDestination(build, workspace, expandedOutputPath, StringUtils.join(modifyMasksforSplittedOutput(new String[]{expandedOutputFileName}), ","), launcher, listener);
}

//Save other configured files to build dir
//Save other configured files to destination dir
if (StringUtils.isNotBlank(getOtherFiles())) {
String filemask = buildEnv.expand(getOtherFiles());
copyFilesToBuildDir(build, workspace, expandedOutputPath, filemask);
copyFilesToDestination(build, workspace, expandedOutputPath, filemask, launcher, listener);
}
logger.println(Messages.robot_publisher_done());
}

logger.println(Messages.robot_publisher_assigning());

String label = buildEnv.expand(overwriteXAxisLabel);
RobotBuildAction action = new RobotBuildAction(build, result, getArchiveDirName(), listener, expandedReportFileName, expandedLogFileName, enableCache, label, countSkippedTests);
RobotBuildAction action = new RobotBuildAction(build, result, getArchiveDirName(), listener,
expandedReportFileName, expandedLogFileName, enableCache, label, countSkippedTests, useArtifactManager);
build.addAction(action);

// set RobotProjectAction as project action
Expand Down Expand Up @@ -339,7 +358,29 @@
}

/**
* Copy files with given filemasks from input path relative to build into specific build file archive dir
* Copy files with given filemasks from input path relative to build into
* local build archive dir or artifact manager destination
*
* @param build The Jenkins run
* @param workspace Build workspace
* @param inputPath Base path for copy. Relative to build workspace.
* @param filemaskToCopy List of Ant GLOB style filemasks to copy from dirs specified at inputPathMask
* @param launcher A way to start processes
* @param listener A place to send output
* @throws IOException thrown exception
* @throws InterruptedException thrown exception
*/
public void copyFilesToDestination(Run<?, ?> build, FilePath workspace, String inputPath, String filemaskToCopy,
Launcher launcher, TaskListener listener) throws IOException, InterruptedException {
if (getUseArtifactManager()) {

Check warning on line 375 in src/main/java/hudson/plugins/robot/RobotPublisher.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 375 is only partially covered, one branch is missing
archiveFilesToDestination(build, workspace, inputPath, filemaskToCopy, launcher, listener);

Check warning on line 376 in src/main/java/hudson/plugins/robot/RobotPublisher.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 376 is not covered by tests
} else {
copyFilesToBuildDir(build, workspace, inputPath, filemaskToCopy);
}
}

/**
* Copy files with given filemasks from input path relative to build into local build file archive dir
*
* @param build The Jenkins run
* @param inputPath Base path for copy. Relative to build workspace.
Expand All @@ -351,11 +392,55 @@
public void copyFilesToBuildDir(Run<?, ?> build, FilePath workspace,
String inputPath, String filemaskToCopy) throws IOException, InterruptedException {
FilePath srcDir = new FilePath(workspace, inputPath);
FilePath destDir = new FilePath(new FilePath(build.getRootDir()),
getArchiveDirName());
FilePath destDir = new FilePath(new FilePath(build.getRootDir()), getArchiveDirName());
srcDir.copyRecursiveTo(filemaskToCopy, destDir);
}

/**
* Copy files with given filemasks from input path relative to Artifact Manager
*
* @param build The Jenkins run
* @param workspace Build workspace
* @param inputPath Base path for copy. Relative to build workspace.
* @param artifactsFilemask List of Ant GLOB style filemasks to copy from dirs specified at inputPathMask
* @param launcher A way to start processes
* @param listener A place to send output
* @throws IOException thrown exception
* @throws InterruptedException thrown exception
*/
public void archiveFilesToDestination(Run<?, ?> build, FilePath workspace, String inputPath, String artifactsFilemask,
Launcher launcher, TaskListener listener) throws IOException, InterruptedException {
FilePath srcDir = new FilePath(workspace, inputPath);
FilePath[] artifactFiles = srcDir.list(artifactsFilemask);

Map<String, String> artifacts = new HashMap<>();
for (FilePath file : artifactFiles) {
// Use relative path as artifact name
String pathInArchiveArea = getRelativePath(srcDir, file);
String pathInWorkspaceArea = getRelativePath(workspace, file);
artifacts.put(pathInArchiveArea, pathInWorkspaceArea);
}

// This will automatically use the configured artifact manager (S3, etc.)
ArtifactManager artifactManager = build.pickArtifactManager();
artifactManager.archive(srcDir, launcher, (BuildListener)listener, artifacts);
if (artifacts.isEmpty()) {
listener.getLogger().println("No artifacts to archive");
} else {
for (Map.Entry<String,String> artifact : artifacts.entrySet()) {
listener.getLogger().println("The artifact to archive: " + artifact.getKey() + "->" + artifact.getValue());
}
}
}

private String getRelativePath(FilePath path1, FilePath path2) {
Path javaPath1 = Paths.get(path1.getRemote());
Path javaPath2 = Paths.get(path2.getRemote());
Path relativeJavaPath = javaPath1.relativize(javaPath2);

return relativeJavaPath.toString();

Check warning on line 441 in src/main/java/hudson/plugins/robot/RobotPublisher.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 413-441 are not covered by tests
}

/**
* Return filename without file suffix.
*
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/hudson/plugins/robot/RobotStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
private boolean enableCache = true;
private boolean countSkippedTests = false;
private @CheckForNull String overwriteXAxisLabel;
private boolean useArtifactManager = false;



Expand Down Expand Up @@ -96,7 +97,11 @@
public String getOverwriteXAxisLabel() {
return this.overwriteXAxisLabel;
}


public boolean getUseArtifactManager() {
return this.useArtifactManager;
}

@DataBoundSetter
public void setArchiveDirName(String archiveDirName) {
this.archiveDirName = Util.fixEmpty(archiveDirName);
Expand Down Expand Up @@ -159,6 +164,11 @@
this.overwriteXAxisLabel = overwriteXAxisLabel;
}

@DataBoundSetter
public void setUseArtifactManager(boolean useArtifactManager) {
this.useArtifactManager = useArtifactManager;
}

Check warning on line 170 in src/main/java/hudson/plugins/robot/RobotStep.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 169-170 are not covered by tests

@Override
public StepExecution start(StepContext context) throws Exception {
return new RobotStepExecution(this, context);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/hudson/plugins/robot/RobotStepExecution.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class RobotStepExecution extends SynchronousNonBlockingStepExecution<Void
@Override protected Void run() throws Exception {
FilePath workspace = getContext().get(FilePath.class);
workspace.mkdirs();
RobotPublisher rp = new RobotPublisher(step.getArchiveDirName(), step.getOutputPath(), step.getOutputFileName(), step.getDisableArchiveOutput(), step.getReportFileName(), step.getLogFileName(), step.getPassThreshold(), step.getUnstableThreshold(), step.getCountSkippedTests(), step.getOtherFiles(), step.getEnableCache(), step.getOverwriteXAxisLabel());
RobotPublisher rp = new RobotPublisher(step.getArchiveDirName(), step.getOutputPath(), step.getOutputFileName(), step.getDisableArchiveOutput(), step.getReportFileName(), step.getLogFileName(), step.getPassThreshold(), step.getUnstableThreshold(), step.getCountSkippedTests(), step.getOtherFiles(), step.getEnableCache(), step.getOverwriteXAxisLabel(), step.getUseArtifactManager());
rp.perform(getContext().get(Run.class), workspace, getContext().get(EnvVars.class), getContext().get(Launcher.class), getContext().get(TaskListener.class));
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ public String evaluate(Run<?, ?> context, FilePath workspace, TaskListener liste
if (action!=null){
String rootURL = (Jenkins.getInstanceOrNull() != null) ? Jenkins.get().getRootUrl() : "";
if (action.getLogFileLink() == null)
return rootURL + context.getUrl()+ action.getUrlName() + "/report/";
return rootURL + context.getUrl()+ action.getReportUrlName();
else
return rootURL + context.getUrl()+ action.getUrlName() + "/report/" + action.getLogFileLink();
return rootURL + context.getUrl()+ action.getReportUrlName() + action.getLogFileLink();
}
return "";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ limitations under the License.
<f:entry title="${%advanced.overwriteXAxisLabel}" description="${%advanced.overwriteXAxisLabel.description}" field="overwriteXAxisLabel">
<f:textbox />
</f:entry>
<f:entry title="${%advanced.useArtifactManager}" description="${%advanced.useArtifactManager.description}" field="useArtifactManager">
<f:checkbox default="false"/>
</f:entry>
</f:advanced>
<f:entry title="${%thresholds.label}" help="/plugin/robot/help-thresholds.html">
<table width="100%">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ advanced.enableCache=Enable cache
advanced.enableCache.description=Enable cache for test results
advanced.overwriteXAxisLabel=X-axis label
advanced.overwriteXAxisLabel.description=Overwrite default x-axis label for publish trend. You can use $display_name to change the label for the build display name.
advanced.useArtifactManager=Use Artifact Manager
advanced.useArtifactManager.description=Use Artifact Manager to copy tests results


thresholds.label=Thresholds for build result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ limitations under the License.
<f:entry title="${%advanced.overwriteXAxisLabel}" description="${%advanced.overwriteXAxisLabel.description}" field="overwriteXAxisLabel">
<f:textbox />
</f:entry>
<f:entry title="${%advanced.useArtifactManager}" description="${%advanced.useArtifactManager.description}" field="useArtifactManager">
<f:checkbox default="false"/>
</f:entry>
</f:advanced>
<f:entry title="${%thresholds.label}" help="/plugin/robot/help-thresholds.html">
<table width="100%">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ advanced.enableCache=Enable cache
advanced.enableCache.description=Enable cache for test results
advanced.overwriteXAxisLabel=X-axis label
advanced.overwriteXAxisLabel.description=Overwrite default x-axis label for publish trend
advanced.useArtifactManager=Use Artifact Manager
advanced.useArtifactManager.description=Use Artifact Manager to copy tests results

thresholds.label=Thresholds for build result
thresholds.countSkippedTests=Include skipped tests in total count for thresholds
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ limitations under the License.
<tr><th>Message:</th><td class="error-message">${it.errorMsg}</td></tr>
</j:if>
<j:if test="${it.hasLog}">
<tr><th>Log File:</th><td><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.urlName}/report/${it.logFile}#${it.id}">${it.logFile}</a></td></tr>
<tr><th>Log File:</th><td><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.reportUrlName}${it.logFile}#${it.id}">${it.logFile}</a></td></tr>
</j:if>
</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ limitations under the License.
<tr><th>Duration:</th><td>${it.humanReadableDuration} (${it.getDurationDiff(prevresult)})</td></tr>
<tr><th>Status:</th><td>${it.overallTotal} test total (${h.getDiffString(it.total - prevresult.total)}), ${it.passed} passed, <span class="${total_status}">${it.failed}</span> failed, ${it.skipped} skipped</td></tr>
<tr><th>Results:</th><td>
<j:if test="${it.hasReport}"><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.urlName}/report/${it.reportFile}">${it.reportFile}</a><br/></j:if>
<j:if test="${it.hasLog}"><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.urlName}/report/${it.logFile}">${it.logFile}</a><br/></j:if>
<j:if test="${it.hasReport}"><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.reportUrlName}${it.reportFile}">${it.reportFile}</a><br/></j:if>
<j:if test="${it.hasLog}"><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.reportUrlName}${it.logFile}">${it.logFile}</a><br/></j:if>
<a href="report">Original result files</a>
</td></tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ limitations under the License.
<tr><th>Duration:</th><td>${it.humanReadableDuration} (${it.getDurationDiff(prevresult)})</td></tr>
<tr><th>Status:</th><td>${it.total} test total (${h.getDiffString(it.total - prevresult.total)}), ${it.passed} passed, <span class="${total_status}">${it.failed}</span> failed, ${it.skipped} skipped</td></tr>
<j:if test="${it.hasReport}">
<tr><th>Report File:</th><td><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.urlName}/report/${it.reportFile}#suites?${it.id}">${it.reportFile}</a></td></tr>
<tr><th>Report File:</th><td><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.reportUrlName}${it.reportFile}#suites?${it.id}">${it.reportFile}</a></td></tr>
</j:if>
<j:if test="${it.hasLog}">
<tr><th>Log File:</th><td><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.urlName}/report/${it.logFile}#${it.id}">${it.logFile}</a></td></tr>
<tr><th>Log File:</th><td><a href="${rootURL}/${it.parentAction.owner.url}${it.parentAction.reportUrlName}${it.logFile}#${it.id}">${it.logFile}</a></td></tr>
</j:if>
</tbody>
</table>
Expand Down
Loading