Skip to content

Commit

Permalink
Merge pull request #72 from mathworks/CI-368-add-new-builders
Browse files Browse the repository at this point in the history
Separate build steps by adding two new builders
  • Loading branch information
nbhoski authored Mar 3, 2020
2 parents 5014017 + 06f1582 commit c093ee9
Show file tree
Hide file tree
Showing 30 changed files with 2,182 additions and 27 deletions.
52 changes: 51 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,31 @@
<url>http:/jenkinsci/matlab-plugin</url>
<tag>HEAD</tag>
</scm>

<build>
<plugins>
<!-- Plugin to download the matlab run scripts and keep it under class
resource folder -->
<plugin>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<id>get-matlab-runner-scripts</id>
<phase>validate</phase>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<url>https://ssd.mathworks.com/supportfiles/ci/run-matlab-command/v0/run-matlab-command.zip</url>
<unpack>true</unpack>
<outputDirectory>${basedir}/src/main/resources</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
Expand Down Expand Up @@ -92,6 +115,33 @@
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<!-- Delete the runner files during clean operation -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>default-clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
<configuration>
<filesets>
<fileset>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/*.bat</include>
<include>**/*.sh</include>
<include>**/*.txt</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/com/mathworks/ci/FormValidationUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.mathworks.ci;

/**
* Copyright 2019-2020 The MathWorks, Inc.
*
* This is Utility class which provides commonly used methods for form validations across builders
*
*/
import java.util.List;
import java.util.function.Function;
import hudson.util.FormValidation;
import hudson.util.FormValidation.Kind;

public class FormValidationUtil {

public static FormValidation getFirstErrorOrWarning(
List<Function<String, FormValidation>> validations, String validationArg) {
if (validations == null || validations.isEmpty())
return FormValidation.ok();
try {
for (Function<String, FormValidation> val : validations) {
FormValidation validationResult = val.apply(validationArg);
if (validationResult.kind.compareTo(Kind.ERROR) == 0
|| validationResult.kind.compareTo(Kind.WARNING) == 0) {
return validationResult;
}
}
} catch (Exception e) {
return FormValidation.warning(Message.getValue("Builder.invalid.matlab.root.warning"));
}
return FormValidation.ok();
}
}
81 changes: 81 additions & 0 deletions src/main/java/com/mathworks/ci/MatlabBuild.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.mathworks.ci;
/**
* Copyright 2019-2020 The MathWorks, Inc.
*
* Build Interface has two default methods. MATLAB builders can override the
* default behavior.
*
*/

import java.io.IOException;
import java.io.InputStream;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Launcher.ProcStarter;
import hudson.model.Computer;
import hudson.model.TaskListener;

public interface MatlabBuild {

/**
* This Method decorates the launcher with MATLAB command provided and returns the Process
* object to launch MATLAB with appropriate startup options like -r or -batch
* @param workspace Current build workspace
* @param launcher Current build launcher
* @param listener Current build listener
* @param envVars Environment variables of the current build
* @param matlabCommand MATLAB command to execute on shell
* @return matlabLauncher returns the process launcher to run MATLAB commands
*/
default ProcStarter getProcessToRunMatlabCommand(FilePath workspace, Launcher launcher,TaskListener listener, EnvVars envVars, String matlabCommand) throws IOException, InterruptedException {
//Get node specific tmp directory to copy matlab runner script
String tmpDir = getNodeSpecificTmpFolderPath();
FilePath targetWorkspace = new FilePath(launcher.getChannel(), tmpDir);
ProcStarter matlabLauncher;
if(launcher.isUnix()) {
matlabLauncher = launcher.launch().pwd(workspace).envs(envVars).cmds(tmpDir+"/run_matlab_command.sh",matlabCommand).stdout(listener);

//Copy runner .sh for linux platform in workspace.
copyFileInWorkspace(MatlabBuilderConstants.SHELL_RUNNER_SCRIPT, "Builder.matlab.runner.script.target.file.linux.name", targetWorkspace);
}else {
launcher = launcher.decorateByPrefix("cmd.exe","/C");
matlabLauncher = launcher.launch().pwd(workspace).envs(envVars).cmds(tmpDir+"\\"+"run_matlab_command.bat","\""+matlabCommand+"\"").stdout(listener);
//Copy runner.bat for Windows platform in workspace.
copyFileInWorkspace(MatlabBuilderConstants.BAT_RUNNER_SCRIPT, "Builder.matlab.runner.script.target.file.windows.name", targetWorkspace);
}
return matlabLauncher;
}

/**
* Method to copy given file from source to target node specific workspace.
*/
default void copyFileInWorkspace(String sourceFile, String targetFile,
FilePath targetWorkspace) throws IOException, InterruptedException {
final ClassLoader classLoader = getClass().getClassLoader();
FilePath targetFilePath = new FilePath(targetWorkspace, Message.getValue(targetFile));
InputStream in = classLoader.getResourceAsStream(sourceFile);
targetFilePath.copyFrom(in);
// set executable permission
targetFilePath.chmod(0755);

}

default FilePath getNodeSpecificMatlabRunnerScript(Launcher launcher) throws IOException, InterruptedException {
Computer cmp = Computer.currentComputer();
String tmpDir = (String) cmp.getSystemProperties().get("java.io.tmpdir");
if(launcher.isUnix()) {
tmpDir = tmpDir+"/run_matlab_command.sh";
}else {
tmpDir = tmpDir+"\\"+"run_matlab_command.bat";
}
return new FilePath(launcher.getChannel(), tmpDir);
}

default String getNodeSpecificTmpFolderPath() throws IOException, InterruptedException {
Computer cmp = Computer.currentComputer();
String tmpDir = (String) cmp.getSystemProperties().get("java.io.tmpdir");
return tmpDir;
}

}
7 changes: 3 additions & 4 deletions src/main/java/com/mathworks/ci/MatlabBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -113,7 +110,9 @@ public void setMatlabRoot(String matlabRoot) {
// Overridden Method used to show the text under build dropdown
@Override
public String getDisplayName() {
return Message.getBuilderDisplayName();
// No name for this descriptor as its deprecated all the jobs will be
// automatically delegated to the new TestRun or Script builders.
return "";
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/mathworks/ci/MatlabBuilderConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ public class MatlabBuilderConstants {
static final String STM_RESULTS = "'SimulinkTestResults'";
static final String COBERTURA_CODE_COVERAGE = "'CoberturaCodeCoverage'";
static final String COBERTURA_MODEL_COVERAGE = "'CoberturaModelCoverage'";

// Matlab Runner files
static final String BAT_RUNNER_SCRIPT = "run_matlab_command.bat";
static final String SHELL_RUNNER_SCRIPT = "run_matlab_command.sh";
}
131 changes: 131 additions & 0 deletions src/main/java/com/mathworks/ci/RunMatlabCommandBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package com.mathworks.ci;
/**
* Copyright 2019-2020 The MathWorks, Inc.
*
* Script builder used to run custom MATLAB commands or scripts.
*
*/

import java.io.IOException;
import javax.annotation.Nonnull;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.StaplerRequest;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Launcher.ProcStarter;
import hudson.model.AbstractProject;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import jenkins.tasks.SimpleBuildStep;
import net.sf.json.JSONObject;

public class RunMatlabCommandBuilder extends Builder implements SimpleBuildStep, MatlabBuild {
private int buildResult;
private EnvVars env;
private String matlabCommand;

@DataBoundConstructor
public RunMatlabCommandBuilder() {

}


// Getter and Setters to access local members


@DataBoundSetter
public void setMatlabCommand(String matlabCommand) {
this.matlabCommand = matlabCommand;
}

public String getMatlabCommand() {
return this.matlabCommand;
}

private String getCommand() {
return this.env == null ? getMatlabCommand() : this.env.expand(getMatlabCommand());
}

private void setEnv(EnvVars env) {
this.env = env;
}

private EnvVars getEnv() {
return this.env;
}

@Symbol("RunMatlabCommand")
@Extension
public static class RunMatlabCommandDescriptor extends BuildStepDescriptor<Builder> {

// Overridden Method used to show the text under build dropdown
@Override
public String getDisplayName() {
return Message.getValue("Builder.script.builder.display.name");
}

@Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
save();
return super.configure(req, formData);
}

/*
* This is to identify which project type in jenkins this should be applicable.(non-Javadoc)
*
* @see hudson.tasks.BuildStepDescriptor#isApplicable(java.lang.Class)
*
* if it returns true then this build step will be applicable for all project type.
*/
@Override
public boolean isApplicable(
@SuppressWarnings("rawtypes") Class<? extends AbstractProject> jobtype) {
return true;
}
}

@Override
public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace,
@Nonnull Launcher launcher, @Nonnull TaskListener listener)
throws InterruptedException, IOException {

try {
// Set the environment variable specific to the this build
setEnv(build.getEnvironment(listener));

// Invoke MATLAB command and transfer output to standard
// Output Console

buildResult = execMatlabCommand(workspace, launcher, listener, getEnv());

if (buildResult != 0) {
build.setResult(Result.FAILURE);
}
} finally {
// Cleanup the runner File from tmp directory
FilePath matlabRunnerScript = getNodeSpecificMatlabRunnerScript(launcher);
if(matlabRunnerScript.exists()) {
matlabRunnerScript.delete();
}
}
}

private synchronized int execMatlabCommand(FilePath workspace, Launcher launcher,
TaskListener listener, EnvVars envVars) throws IOException, InterruptedException {
ProcStarter matlabLauncher;
try {
matlabLauncher = getProcessToRunMatlabCommand(workspace, launcher, listener, envVars,getCommand());
} catch (Exception e) {
listener.getLogger().println(e.getMessage());
return 1;
}
return matlabLauncher.join();
}
}
Loading

0 comments on commit c093ee9

Please sign in to comment.