From 5c473a4b0a4fd434af555e144451b549371198af Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Fri, 15 Jun 2018 10:41:56 -0700 Subject: [PATCH] [JENKINS-34983] - Add pipeline support (#12) * Add pipeline support * Update POM version * Add automated tests * Add Jenkinsfile * Fix FindBugs warnings --- Jenkinsfile | 1 + pom.xml | 43 +++- .../textfinder/TextFinderPublisher.java | 194 +++++++++++------- .../plugins/textfinder/Messages.properties | 2 +- .../TextFinderPublisher/config.jelly | 1 + src/main/resources/index.jelly | 1 + .../TextFinderPublisherAgentTest.java | 86 ++++++++ .../TextFinderPublisherFreestyleTest.java | 104 ++++++++++ .../TextFinderPublisherPipelineTest.java | 160 +++++++++++++++ 9 files changed, 519 insertions(+), 73 deletions(-) create mode 100644 Jenkinsfile create mode 100644 src/test/java/hudson/plugins/textfinder/TextFinderPublisherAgentTest.java create mode 100644 src/test/java/hudson/plugins/textfinder/TextFinderPublisherFreestyleTest.java create mode 100644 src/test/java/hudson/plugins/textfinder/TextFinderPublisherPipelineTest.java diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..ed021b6 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1 @@ +buildPlugin(jenkinsVersions: [null, '2.121.1']) diff --git a/pom.xml b/pom.xml index 44b4a7f..5d53306 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,8 @@ org.jenkins-ci.plugins plugin - 1.480 + 3.15 + text-finder @@ -12,6 +13,10 @@ 1.11-SNAPSHOT Jenkins TextFinder plugin http://wiki.jenkins-ci.org/display/JENKINS/Text-finder+Plugin + + 1.651 + 7 + @@ -28,17 +33,49 @@ https://github.com/jenkinsci/${project.artifactId}-plugin + + + org.jenkins-ci.plugins + structs + 1.3 + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + 2.1 + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + 2.10 + test + + + org.jenkins-ci.plugins.workflow + workflow-durable-task-step + 2.4 + test + + + org.jenkins-ci.plugins.workflow + workflow-job + 2.4 + test + + + repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ + https://repo.jenkins-ci.org/public/ repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ + https://repo.jenkins-ci.org/public/ diff --git a/src/main/java/hudson/plugins/textfinder/TextFinderPublisher.java b/src/main/java/hudson/plugins/textfinder/TextFinderPublisher.java index 9d0f0a4..fec36f4 100644 --- a/src/main/java/hudson/plugins/textfinder/TextFinderPublisher.java +++ b/src/main/java/hudson/plugins/textfinder/TextFinderPublisher.java @@ -1,14 +1,14 @@ package hudson.plugins.textfinder; -import hudson.FilePath.FileCallable; +import hudson.FilePath; import hudson.Launcher; import hudson.Util; import hudson.Extension; import static hudson.Util.fixEmpty; -import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.BuildListener; import hudson.model.Result; +import hudson.model.Run; +import hudson.model.TaskListener; import hudson.remoting.RemoteOutputStream; import hudson.remoting.VirtualChannel; import hudson.tasks.BuildStepDescriptor; @@ -16,17 +16,22 @@ import hudson.tasks.Publisher; import hudson.tasks.Recorder; import hudson.util.FormValidation; +import jenkins.MasterToSlaveFileCallable; +import jenkins.tasks.SimpleBuildStep; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.types.FileSet; import org.apache.commons.io.IOUtils; +import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import javax.servlet.ServletException; import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintStream; import java.io.Serializable; import java.util.regex.Matcher; @@ -39,24 +44,20 @@ * * @author Santiago.PericasGeertsen@sun.com */ -public class TextFinderPublisher extends Recorder implements Serializable { +public class TextFinderPublisher extends Recorder implements Serializable, SimpleBuildStep { - public final String fileSet; + public String fileSet; public final String regexp; - public final boolean succeedIfFound; - public final boolean unstableIfFound; + public boolean succeedIfFound; + public boolean unstableIfFound; /** * True to also scan the whole console output */ - public final boolean alsoCheckConsoleOutput; + public boolean alsoCheckConsoleOutput; @DataBoundConstructor - public TextFinderPublisher(String fileSet, String regexp, boolean succeedIfFound, boolean unstableIfFound, boolean alsoCheckConsoleOutput) { - this.fileSet = Util.fixEmpty(fileSet.trim()); + public TextFinderPublisher(String regexp) { this.regexp = regexp; - this.succeedIfFound = succeedIfFound; - this.unstableIfFound = unstableIfFound; - this.alsoCheckConsoleOutput = alsoCheckConsoleOutput; // Attempt to compile regular expression try { @@ -66,13 +67,49 @@ public TextFinderPublisher(String fileSet, String regexp, boolean succeedIfFound } } + @Deprecated + public TextFinderPublisher( + String fileSet, + String regexp, + boolean succeedIfFound, + boolean unstableIfFound, + boolean alsoCheckConsoleOutput) { + this(regexp); + this.fileSet = Util.fixEmpty(fileSet.trim()); + this.succeedIfFound = succeedIfFound; + this.unstableIfFound = unstableIfFound; + this.alsoCheckConsoleOutput = alsoCheckConsoleOutput; + } + + @DataBoundSetter + public void setFileSet(String fileSet) { + this.fileSet = Util.fixEmpty(fileSet.trim()); + } + + @DataBoundSetter + public void setSucceedIfFound(boolean succeedIfFound) { + this.succeedIfFound = succeedIfFound; + } + + @DataBoundSetter + public void setUnstableIfFound(boolean unstableIfFound) { + this.unstableIfFound = unstableIfFound; + } + + @DataBoundSetter + public void setAlsoCheckConsoleOutput(boolean alsoCheckConsoleOutput) { + this.alsoCheckConsoleOutput = alsoCheckConsoleOutput; + } + + @Override public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; } - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - findText(build, listener.getLogger()); - return true; + @Override + public void perform(Run run, FilePath workspace, Launcher launcher, TaskListener listener) + throws InterruptedException, IOException { + findText(run, workspace, listener); } /** @@ -81,13 +118,16 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen private static final class AbortException extends RuntimeException { } - private void findText(AbstractBuild build, PrintStream logger) throws IOException, InterruptedException { + private void findText(Run run, FilePath workspace, TaskListener listener) + throws IOException, InterruptedException { try { + PrintStream logger = listener.getLogger(); boolean foundText = false; if(alsoCheckConsoleOutput) { logger.println("Checking console output"); - foundText |= checkFile(build.getLogFile(), compilePattern(logger), logger, true); + foundText |= + checkFile(run.getLogFile(), compilePattern(logger, regexp), logger, true); } else { // printing this when checking console output will cause the plugin // to find this line, which would be pointless. @@ -98,57 +138,14 @@ private void findText(AbstractBuild build, PrintStream logger) throws IOExceptio final RemoteOutputStream ros = new RemoteOutputStream(logger); if(fileSet!=null) { - foundText |= build.getWorkspace().act(new FileCallable() { - public Boolean invoke(File ws, VirtualChannel channel) throws IOException { - PrintStream logger = new PrintStream(ros); - - // Collect list of files for searching - FileSet fs = new FileSet(); - org.apache.tools.ant.Project p = new org.apache.tools.ant.Project(); - fs.setProject(p); - fs.setDir(ws); - fs.setIncludes(fileSet); - DirectoryScanner ds = fs.getDirectoryScanner(p); - - // Any files in the final set? - String[] files = ds.getIncludedFiles(); - if (files.length == 0) { - logger.println("Jenkins Text Finder: File set '" + - fileSet + "' is empty"); - throw new AbortException(); - } - - Pattern pattern = compilePattern(logger); - - boolean foundText = false; - - for (String file : files) { - File f = new File(ws, file); - - if (!f.exists()) { - logger.println("Jenkins Text Finder: Unable to" + - " find file '" + f + "'"); - continue; - } - if (!f.canRead()) { - logger.println("Jenkins Text Finder: Unable to" + - " read from file '" + f + "'"); - continue; - } - - foundText |= checkFile(f, pattern, logger, false); - } - - return foundText; - } - }); + foundText |= workspace.act(new FileChecker(ros, fileSet, regexp)); } if (foundText != succeedIfFound) - build.setResult(unstableIfFound ? Result.UNSTABLE : Result.FAILURE); + run.setResult(unstableIfFound ? Result.UNSTABLE : Result.FAILURE); } catch (AbortException e) { // no test file found - build.setResult(Result.UNSTABLE); + run.setResult(Result.UNSTABLE); } } @@ -159,14 +156,15 @@ public Boolean invoke(File ws, VirtualChannel channel) throws IOException { * true to return immediately as soon as the first hit is found. this is necessary * when we are scanning the console output, because otherwise we'll loop forever. */ - private boolean checkFile(File f, Pattern pattern, PrintStream logger, boolean abortAfterFirstHit) { + private static boolean checkFile( + File f, Pattern pattern, PrintStream logger, boolean abortAfterFirstHit) { boolean logFilename = true; boolean foundText = false; BufferedReader reader=null; try { // Assume default encoding and text files String line; - reader = new BufferedReader(new FileReader(f)); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8")); while ((line = reader.readLine()) != null) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { @@ -189,7 +187,7 @@ private boolean checkFile(File f, Pattern pattern, PrintStream logger, boolean a return foundText; } - private Pattern compilePattern(PrintStream logger) { + private static Pattern compilePattern(PrintStream logger, String regexp) { Pattern pattern; try { pattern = Pattern.compile(regexp); @@ -201,10 +199,12 @@ private Pattern compilePattern(PrintStream logger) { return pattern; } + @Symbol("findText") @Extension public static final class DescriptorImpl extends BuildStepDescriptor { + @Override public String getDisplayName() { - return Messages.DisplayName(); + return Messages.TextFinderPublisher_DisplayName(); } @Override @@ -212,6 +212,7 @@ public String getHelpFile() { return "/plugin/text-finder/help.html"; } + @Override public boolean isApplicable(Class jobType) { return true; } @@ -233,6 +234,61 @@ public FormValidation doCheckRegexp(@QueryParameter String value) throws IOExcep } } + private static class FileChecker extends MasterToSlaveFileCallable { + + private final RemoteOutputStream ros; + private final String fileSet; + private final String regexp; + + public FileChecker(RemoteOutputStream ros, String fileSet, String regexp) { + this.ros = ros; + this.fileSet = fileSet; + this.regexp = regexp; + } + + @Override + public Boolean invoke(File ws, VirtualChannel channel) throws IOException { + PrintStream logger = new PrintStream(ros, false, "UTF-8"); + + // Collect list of files for searching + FileSet fs = new FileSet(); + org.apache.tools.ant.Project p = new org.apache.tools.ant.Project(); + fs.setProject(p); + fs.setDir(ws); + fs.setIncludes(fileSet); + DirectoryScanner ds = fs.getDirectoryScanner(p); + + // Any files in the final set? + String[] files = ds.getIncludedFiles(); + if (files.length == 0) { + logger.println("Jenkins Text Finder: File set '" + fileSet + "' is empty"); + throw new AbortException(); + } + + Pattern pattern = compilePattern(logger, regexp); + + boolean foundText = false; + + for (String file : files) { + File f = new File(ws, file); + + if (!f.exists()) { + logger.println("Jenkins Text Finder: Unable to" + " find file '" + f + "'"); + continue; + } + if (!f.canRead()) { + logger.println( + "Jenkins Text Finder: Unable to" + " read from file '" + f + "'"); + continue; + } + + foundText |= checkFile(f, pattern, logger, false); + } + + return foundText; + } + } + private static final long serialVersionUID = 1L; } diff --git a/src/main/resources/hudson/plugins/textfinder/Messages.properties b/src/main/resources/hudson/plugins/textfinder/Messages.properties index c786f57..af5ebc7 100755 --- a/src/main/resources/hudson/plugins/textfinder/Messages.properties +++ b/src/main/resources/hudson/plugins/textfinder/Messages.properties @@ -1 +1 @@ -DisplayName=Jenkins Text Finder +TextFinderPublisher.DisplayName=Jenkins Text Finder diff --git a/src/main/resources/hudson/plugins/textfinder/TextFinderPublisher/config.jelly b/src/main/resources/hudson/plugins/textfinder/TextFinderPublisher/config.jelly index fe51541..2c79b0d 100644 --- a/src/main/resources/hudson/plugins/textfinder/TextFinderPublisher/config.jelly +++ b/src/main/resources/hudson/plugins/textfinder/TextFinderPublisher/config.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/index.jelly b/src/main/resources/index.jelly index 943cac6..1bc97d3 100644 --- a/src/main/resources/index.jelly +++ b/src/main/resources/index.jelly @@ -1,3 +1,4 @@ +
This plugin is used to search for strings in workspace files. The outcome of this search can be used to mark the build as normal or failed. diff --git a/src/test/java/hudson/plugins/textfinder/TextFinderPublisherAgentTest.java b/src/test/java/hudson/plugins/textfinder/TextFinderPublisherAgentTest.java new file mode 100644 index 0000000..dc26bc1 --- /dev/null +++ b/src/test/java/hudson/plugins/textfinder/TextFinderPublisherAgentTest.java @@ -0,0 +1,86 @@ +package hudson.plugins.textfinder; + +import hudson.Functions; +import hudson.model.Result; +import hudson.slaves.DumbSlave; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.jenkinsci.plugins.workflow.actions.WorkspaceAction; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker; +import org.jenkinsci.plugins.workflow.graph.FlowNode; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class TextFinderPublisherAgentTest { + + private static final String UNIQUE_TEXT = "foobar"; + private static final String ECHO_UNIQUE_TEXT = "echo " + UNIQUE_TEXT; + + @Rule public JenkinsRule rule = new JenkinsRule(); + + private void assertLogContainsMatch(File file, String text, WorkflowRun build, boolean isShell) + throws IOException { + String prompt; + if (isShell) { + prompt = Functions.isWindows() ? ">" : "+ "; + } else { + prompt = ""; + } + rule.assertLogContains( + String.format( + "%s:%s%s%s", file, System.getProperty("line.separator"), prompt, text), + build); + } + + private File getWorkspace(WorkflowRun build) { + FlowGraphWalker walker = new FlowGraphWalker(build.getExecution()); + List actions = new ArrayList<>(); + for (FlowNode node : walker) { + WorkspaceAction action = node.getAction(WorkspaceAction.class); + if (action != null) { + return new File(action.getWorkspace().getRemote()); + } + } + throw new IllegalStateException("Failed to find workspace"); + } + + @Test + public void failureIfFoundInFileOnAgent() throws Exception { + DumbSlave agent = rule.createOnlineSlave(); + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + String.format( + "node('%s') {writeFile file: 'out.txt', text: 'foobar'}\n" + + "node('%s') {findText regexp: 'foobar', fileSet: 'out.txt'}\n", + agent.getNodeName(), agent.getNodeName()))); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking foobar", build); + assertLogContainsMatch(new File(getWorkspace(build), "out.txt"), UNIQUE_TEXT, build, false); + rule.assertBuildStatus(Result.FAILURE, build); + } + + @Test + public void failureIfFoundInConsoleOnAgent() throws Exception { + DumbSlave agent = rule.createOnlineSlave(); + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + String.format( + "node('%s') {isUnix() ? sh('echo foobar') : bat(\"prompt \\$G\\r\\necho foobar\")}\n" + + "node('%s') {findText regexp: 'foobar', alsoCheckConsoleOutput: true}\n", + agent.getNodeName(), agent.getNodeName()))); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.FAILURE, build); + } +} diff --git a/src/test/java/hudson/plugins/textfinder/TextFinderPublisherFreestyleTest.java b/src/test/java/hudson/plugins/textfinder/TextFinderPublisherFreestyleTest.java new file mode 100644 index 0000000..a24bd95 --- /dev/null +++ b/src/test/java/hudson/plugins/textfinder/TextFinderPublisherFreestyleTest.java @@ -0,0 +1,104 @@ +package hudson.plugins.textfinder; + +import hudson.Functions; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import hudson.model.Result; +import hudson.tasks.BatchFile; +import hudson.tasks.CommandInterpreter; +import hudson.tasks.Shell; +import java.io.File; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class TextFinderPublisherFreestyleTest { + + private static final String UNIQUE_TEXT = "foobar"; + private static final String ECHO_UNIQUE_TEXT = "echo " + UNIQUE_TEXT; + + @Rule public JenkinsRule rule = new JenkinsRule(); + + private void assertLogContainsMatch( + File file, String text, FreeStyleBuild build, boolean isShell) throws IOException { + String prompt; + if (isShell) { + prompt = Functions.isWindows() ? ">" : "+ "; + } else { + prompt = ""; + } + rule.assertLogContains( + String.format( + "%s:%s%s%s", file, System.getProperty("line.separator"), prompt, text), + build); + } + + @Test + public void successIfFoundInConsole() throws Exception { + FreeStyleProject project = rule.createFreeStyleProject("freestyle"); + CommandInterpreter command = + Functions.isWindows() + ? new BatchFile("prompt $G\n" + ECHO_UNIQUE_TEXT) + : new Shell(ECHO_UNIQUE_TEXT); + project.getBuildersList().add(command); + TextFinderPublisher textFinder = new TextFinderPublisher(UNIQUE_TEXT); + textFinder.setSucceedIfFound(true); + textFinder.setAlsoCheckConsoleOutput(true); + project.getPublishersList().add(textFinder); + FreeStyleBuild build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.SUCCESS, build); + } + + @Test + public void failureIfFoundInConsole() throws Exception { + FreeStyleProject project = rule.createFreeStyleProject("freestyle"); + CommandInterpreter command = + Functions.isWindows() + ? new BatchFile("prompt $G\n" + ECHO_UNIQUE_TEXT) + : new Shell(ECHO_UNIQUE_TEXT); + project.getBuildersList().add(command); + TextFinderPublisher textFinder = new TextFinderPublisher(UNIQUE_TEXT); + textFinder.setAlsoCheckConsoleOutput(true); + project.getPublishersList().add(textFinder); + FreeStyleBuild build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.FAILURE, build); + } + + @Test + public void unstableIfFoundInConsole() throws Exception { + FreeStyleProject project = rule.createFreeStyleProject("freestyle"); + CommandInterpreter command = + Functions.isWindows() + ? new BatchFile("prompt $G\n" + ECHO_UNIQUE_TEXT) + : new Shell(ECHO_UNIQUE_TEXT); + project.getBuildersList().add(command); + TextFinderPublisher textFinder = new TextFinderPublisher(UNIQUE_TEXT); + textFinder.setUnstableIfFound(true); + textFinder.setAlsoCheckConsoleOutput(true); + project.getPublishersList().add(textFinder); + FreeStyleBuild build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.UNSTABLE, build); + } + + @Test + public void notFoundInConsole() throws Exception { + FreeStyleProject project = rule.createFreeStyleProject("freestyle"); + TextFinderPublisher textFinder = new TextFinderPublisher(UNIQUE_TEXT); + textFinder.setAlsoCheckConsoleOutput(true); + project.getPublishersList().add(textFinder); + FreeStyleBuild build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + rule.assertBuildStatus(Result.SUCCESS, build); + } +} diff --git a/src/test/java/hudson/plugins/textfinder/TextFinderPublisherPipelineTest.java b/src/test/java/hudson/plugins/textfinder/TextFinderPublisherPipelineTest.java new file mode 100644 index 0000000..ad14937 --- /dev/null +++ b/src/test/java/hudson/plugins/textfinder/TextFinderPublisherPipelineTest.java @@ -0,0 +1,160 @@ +package hudson.plugins.textfinder; + +import hudson.Functions; +import hudson.model.Result; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.jenkinsci.plugins.workflow.actions.WorkspaceAction; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker; +import org.jenkinsci.plugins.workflow.graph.FlowNode; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +public class TextFinderPublisherPipelineTest { + + private static final String UNIQUE_TEXT = "foobar"; + private static final String ECHO_UNIQUE_TEXT = "echo " + UNIQUE_TEXT; + + @Rule public JenkinsRule rule = new JenkinsRule(); + + private void assertLogContainsMatch(File file, String text, WorkflowRun build, boolean isShell) + throws IOException { + String prompt; + if (isShell) { + prompt = Functions.isWindows() ? ">" : "+ "; + } else { + prompt = ""; + } + rule.assertLogContains( + String.format( + "%s:%s%s%s", file, System.getProperty("line.separator"), prompt, text), + build); + } + + private File getWorkspace(WorkflowRun build) { + FlowGraphWalker walker = new FlowGraphWalker(build.getExecution()); + List actions = new ArrayList<>(); + for (FlowNode node : walker) { + WorkspaceAction action = node.getAction(WorkspaceAction.class); + if (action != null) { + return new File(action.getWorkspace().getRemote()); + } + } + throw new IllegalStateException("Failed to find workspace"); + } + + @Test + public void successIfFoundInFile() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {writeFile file: 'out.txt', text: 'foobar'}\n" + + "node {findText regexp: 'foobar', fileSet: 'out.txt', succeedIfFound: true}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking foobar", build); + assertLogContainsMatch(new File(getWorkspace(build), "out.txt"), UNIQUE_TEXT, build, false); + rule.assertBuildStatus(Result.SUCCESS, build); + } + + @Test + public void failureIfFoundInFile() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {writeFile file: 'out.txt', text: 'foobar'}\n" + + "node {findText regexp: 'foobar', fileSet: 'out.txt'}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking foobar", build); + assertLogContainsMatch(new File(getWorkspace(build), "out.txt"), UNIQUE_TEXT, build, false); + rule.assertBuildStatus(Result.FAILURE, build); + } + + @Test + public void unstableIfFoundInFile() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {writeFile file: 'out.txt', text: 'foobar'}\n" + + "node {findText regexp: 'foobar', fileSet: 'out.txt', unstableIfFound: true}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking foobar", build); + assertLogContainsMatch(new File(getWorkspace(build), "out.txt"), UNIQUE_TEXT, build, false); + rule.assertBuildStatus(Result.UNSTABLE, build); + } + + @Test + public void notFoundInFile() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {writeFile file: 'out.txt', text: 'foobaz'}\n" + + "node {findText regexp: 'foobar', fileSet: 'out.txt'}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking foobar", build); + rule.assertBuildStatus(Result.SUCCESS, build); + } + + @Test + public void successIfFoundInConsole() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {isUnix() ? sh('echo foobar') : bat(\"prompt \\$G\\r\\necho foobar\")}\n" + + "node {findText regexp: 'foobar', succeedIfFound: true, alsoCheckConsoleOutput: true}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.SUCCESS, build); + } + + @Test + public void failureIfFoundInConsole() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {isUnix() ? sh('echo foobar') : bat(\"prompt \\$G\\r\\necho foobar\")}\n" + + "node {findText regexp: 'foobar', alsoCheckConsoleOutput: true}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.FAILURE, build); + } + + @Test + public void unstableIfFoundInConsole() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {isUnix() ? sh('echo foobar') : bat(\"prompt \\$G\\r\\necho foobar\")}\n" + + "node {findText regexp: 'foobar', unstableIfFound: true, alsoCheckConsoleOutput: true}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + assertLogContainsMatch(build.getLogFile(), ECHO_UNIQUE_TEXT, build, true); + rule.assertBuildStatus(Result.UNSTABLE, build); + } + + @Test + public void notFoundInConsole() throws Exception { + WorkflowJob project = rule.createProject(WorkflowJob.class, "pipeline"); + project.setDefinition( + new CpsFlowDefinition( + "node {findText regexp: 'foobar', alsoCheckConsoleOutput: true}\n")); + WorkflowRun build = project.scheduleBuild2(0).get(); + rule.waitForCompletion(build); + rule.assertLogContains("Checking console output", build); + rule.assertBuildStatus(Result.SUCCESS, build); + } +}