From 0e782d776c50a9348ab8b2cbbad41e671e1735e7 Mon Sep 17 00:00:00 2001 From: Yahav Itschak Date: Sun, 17 Nov 2024 09:43:43 +0200 Subject: [PATCH] Allow capturing JFrog CLI output (#113) --- README.md | 23 ++ .../java/io/jenkins/plugins/jfrog/JfStep.java | 346 +++++++++--------- .../plugins/jfrog/AddBuildInfoActionTest.java | 3 +- .../io/jenkins/plugins/jfrog/JfStepTest.java | 2 +- .../integration/JFrogInstallationITest.java | 11 + .../pipelines/version_output.pipeline | 21 ++ 6 files changed, 234 insertions(+), 172 deletions(-) create mode 100644 src/test/resources/integration/pipelines/version_output.pipeline diff --git a/README.md b/README.md index 879586cd..ffdfcac7 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ - [Setting the build name and build number](#setting-the-build-name-and-the-build-number) - [Using multiple JFrog Platform instances](#using-multiple-jfrog-platform-instances) - [Publishing and accessing the build-info](#publishing-and-accessing-the-build-info) + - [Capturing the output of JFrog CLI commands](#capturing-the-output-of-jfrog-cli-commands) - [Using HTTP/s proxy](#using-https-proxy) - [Jenkins Configuration as Code](#jenkins-configuration-as-code) - [Examples](#examples) @@ -180,6 +181,28 @@ stage('Publish build info') { When the job publishes the build-info to Artifactory, you can access it by clicking on the build-info icon, next to the job run. +### Capturing the output of JFrog CLI commands + +The JFrog CLI commands output is returned as a string. +To capture the output of JFrog CLI commands, wrap the JFrog CLI command in a `script` block: + +```groovy +script { + String version = jf '-v' + echo "JFrog CLI version output: $version" +} +``` + +
+ Scripted Pipeline + +```groovy +String version = jf '-v' +echo "JFrog CLI version output: $version" +``` + +
+ ![build-info.png](images/readme/build-info.png) ## Using HTTP/S proxy diff --git a/src/main/java/io/jenkins/plugins/jfrog/JfStep.java b/src/main/java/io/jenkins/plugins/jfrog/JfStep.java index 9a721ee1..5d2b022f 100644 --- a/src/main/java/io/jenkins/plugins/jfrog/JfStep.java +++ b/src/main/java/io/jenkins/plugins/jfrog/JfStep.java @@ -2,17 +2,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.EnvVars; -import hudson.Extension; -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractProject; +import hudson.*; import hudson.model.Job; import hudson.model.Run; import hudson.model.TaskListener; -import hudson.tasks.BuildStepDescriptor; -import hudson.tasks.Builder; import hudson.util.ArgumentListBuilder; import io.jenkins.plugins.jfrog.actions.BuildInfoBuildBadgeAction; import io.jenkins.plugins.jfrog.actions.JFrogCliConfigEncryption; @@ -21,11 +14,11 @@ import io.jenkins.plugins.jfrog.configuration.JFrogPlatformInstance; import io.jenkins.plugins.jfrog.models.BuildInfoOutputModel; import io.jenkins.plugins.jfrog.plugins.PluginsUtils; -import jenkins.tasks.SimpleBuildStep; +import lombok.Getter; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.jenkinsci.Symbol; import org.jenkinsci.plugins.plaincredentials.StringCredentials; +import org.jenkinsci.plugins.workflow.steps.*; import org.jfrog.build.api.util.Log; import org.kohsuke.stapler.DataBoundConstructor; @@ -35,6 +28,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.List; +import java.util.Set; import static io.jenkins.plugins.jfrog.JfrogInstallation.JFROG_BINARY_PATH; import static org.apache.commons.lang3.StringUtils.*; @@ -43,10 +37,10 @@ /** * @author gail */ +@Getter @SuppressWarnings("unused") -public class JfStep extends Builder implements SimpleBuildStep { - private final ObjectMapper mapper = createMapper(); - static final String STEP_NAME = "jf"; +public class JfStep extends Step { + private static final ObjectMapper mapper = createMapper(); protected String[] args; @DataBoundConstructor @@ -59,180 +53,188 @@ public JfStep(Object args) { this.args = split(args.toString()); } - public String[] getArgs() { - return args; + @Override + public StepExecution start(StepContext context) { + return new Execution(args, context); } - /** - * Build and run a 'jf' command. - * - * @param run running as a part of a specific build - * @param workspace a workspace to use for any file operations - * @param env environment variables applicable to this step - * @param launcher a way to start processes - * @param listener a place to send output - * @throws InterruptedException if the step is interrupted - * @throws IOException in case of any I/O error, or we failed to run the 'jf' command - */ - @Override - public void perform(@NonNull Run run, @NonNull FilePath workspace, @NonNull EnvVars env, @NonNull Launcher launcher, @NonNull TaskListener listener) throws InterruptedException, IOException { - workspace.mkdirs(); - // Build the 'jf' command - ArgumentListBuilder builder = new ArgumentListBuilder(); - boolean isWindows = !launcher.isUnix(); - String jfrogBinaryPath = getJFrogCLIPath(env, isWindows); + public static class Execution extends SynchronousNonBlockingStepExecution { + private final String[] args; - builder.add(jfrogBinaryPath).add(args); - if (isWindows) { - builder = builder.toWindowsCommand(); + protected Execution(String[] args, @Nonnull StepContext context) { + super(context); + this.args = args; } - try (ByteArrayOutputStream taskOutputStream = new ByteArrayOutputStream()) { - JfTaskListener jfTaskListener = new JfTaskListener(listener, taskOutputStream); - Launcher.ProcStarter jfLauncher = setupJFrogEnvironment(run, env, launcher, jfTaskListener, workspace, jfrogBinaryPath, isWindows); - // Running the 'jf' command - int exitValue = jfLauncher.cmds(builder).join(); - if (exitValue != 0) { - throw new RuntimeException("Running 'jf' command failed with exit code " + exitValue); - } - addBuildInfoActionIfNeeded(new JenkinsBuildInfoLog(listener), run, taskOutputStream); - } catch (Exception e) { - String errorMessage = "Couldn't execute 'jf' command. " + ExceptionUtils.getRootCauseMessage(e); - throw new RuntimeException(errorMessage, e); - } - } + @Override + protected String run() throws Exception { + // Get the step context + Launcher launcher = getContext().get(Launcher.class); + FilePath workspace = getContext().get(FilePath.class); + TaskListener listener = getContext().get(TaskListener.class); + EnvVars env = getContext().get(EnvVars.class); + Run run = getContext().get(Run.class); - /** - * Get JFrog CLI path in agent, according to the JFROG_BINARY_PATH environment variable. - * The JFROG_BINARY_PATH also can be set implicitly in Declarative Pipeline by choosing the JFrog CLI tool or - * explicitly in Scripted Pipeline. - * - * @param env - Job's environment variables - * @param isWindows - True if the agent's OS is windows - * @return JFrog CLI path in agent. - */ - static String getJFrogCLIPath(EnvVars env, boolean isWindows) { - // JFROG_BINARY_PATH is set according to the master OS. If not configured, the value of jfrogBinaryPath will - // eventually be 'jf' or 'jf.exe'. In that case, the JFrog CLI from the system path is used. - String jfrogBinaryPath = Paths.get(env.get(JFROG_BINARY_PATH, ""), Utils.getJfrogCliBinaryName(isWindows)).toString(); + workspace.mkdirs(); + // Build the 'jf' command + ArgumentListBuilder builder = new ArgumentListBuilder(); + boolean isWindows = !launcher.isUnix(); + String jfrogBinaryPath = getJFrogCLIPath(env, isWindows); - // Modify jfrogBinaryPath according to the agent's OS - return isWindows ? - FilenameUtils.separatorsToWindows(jfrogBinaryPath) : - FilenameUtils.separatorsToUnix(jfrogBinaryPath); - } + builder.add(jfrogBinaryPath).add(args); + if (isWindows) { + builder = builder.toWindowsCommand(); + } - /** - * Log if the JFrog CLI binary path doesn't exist in job's environment variable. - * This environment variable exists in one of the following scenarios: - * 1. Declarative Pipeline: A 'jfrog' tool was set - * 2. Scripted Pipeline: Using the "withEnv(["JFROG_BINARY_PATH=${tool 'jfrog-cli'}"])" syntax - * - * @param env - Job's environment variables - * @param listener - Job's logger - */ - private void logIfNoToolProvided(EnvVars env, TaskListener listener) { - if (env.containsKey(JFROG_BINARY_PATH)) { - return; + String output; + try (ByteArrayOutputStream taskOutputStream = new ByteArrayOutputStream()) { + JfTaskListener jfTaskListener = new JfTaskListener(listener, taskOutputStream); + Launcher.ProcStarter jfLauncher = setupJFrogEnvironment(run, env, launcher, jfTaskListener, workspace, jfrogBinaryPath, isWindows); + // Running the 'jf' command + int exitValue = jfLauncher.cmds(builder).join(); + output = taskOutputStream.toString(StandardCharsets.UTF_8); + if (exitValue != 0) { + throw new RuntimeException("Running 'jf' command failed with exit code " + exitValue); + } + addBuildInfoActionIfNeeded(args, new JenkinsBuildInfoLog(listener), run, taskOutputStream); + } catch (Exception e) { + String errorMessage = "Couldn't execute 'jf' command. " + ExceptionUtils.getRootCauseMessage(e); + throw new RuntimeException(errorMessage, e); + } + return output; } - JenkinsBuildInfoLog buildInfoLog = new JenkinsBuildInfoLog(listener); - buildInfoLog.info("A 'jfrog' tool was not set. Using JFrog CLI from the system path."); - } - /** - * Configure all JFrog relevant environment variables and all servers (if they haven't been configured yet). - * - * @param run running as part of a specific build - * @param env environment variables applicable to this step - * @param launcher a way to start processes - * @param listener a place to send output - * @param workspace a workspace to use for any file operations - * @param jfrogBinaryPath path to jfrog cli binary on the filesystem - * @param isWindows is Windows the applicable OS - * @return launcher applicable to this step. - * @throws InterruptedException if the step is interrupted - * @throws IOException in case of any I/O error, or we failed to run the 'jf' command - */ - public Launcher.ProcStarter setupJFrogEnvironment(Run run, EnvVars env, Launcher launcher, TaskListener listener, FilePath workspace, String jfrogBinaryPath, boolean isWindows) throws IOException, InterruptedException { - JFrogCliConfigEncryption jfrogCliConfigEncryption = run.getAction(JFrogCliConfigEncryption.class); - if (jfrogCliConfigEncryption == null) { - // Set up the config encryption action to allow encrypting the JFrog CLI configuration and make sure we only create one key - jfrogCliConfigEncryption = new JFrogCliConfigEncryption(env); - run.addAction(jfrogCliConfigEncryption); + /** + * Get JFrog CLI path in agent, according to the JFROG_BINARY_PATH environment variable. + * The JFROG_BINARY_PATH also can be set implicitly in Declarative Pipeline by choosing the JFrog CLI tool or + * explicitly in Scripted Pipeline. + * + * @param env - Job's environment variables + * @param isWindows - True if the agent's OS is windows + * @return JFrog CLI path in agent. + */ + static String getJFrogCLIPath(EnvVars env, boolean isWindows) { + // JFROG_BINARY_PATH is set according to the master OS. If not configured, the value of jfrogBinaryPath will + // eventually be 'jf' or 'jf.exe'. In that case, the JFrog CLI from the system path is used. + String jfrogBinaryPath = Paths.get(env.get(JFROG_BINARY_PATH, ""), Utils.getJfrogCliBinaryName(isWindows)).toString(); + + // Modify jfrogBinaryPath according to the agent's OS + return isWindows ? + FilenameUtils.separatorsToWindows(jfrogBinaryPath) : + FilenameUtils.separatorsToUnix(jfrogBinaryPath); } - FilePath jfrogHomeTempDir = Utils.createAndGetJfrogCliHomeTempDir(workspace, String.valueOf(run.getNumber())); - CliEnvConfigurator.configureCliEnv(env, jfrogHomeTempDir.getRemote(), jfrogCliConfigEncryption); - Launcher.ProcStarter jfLauncher = launcher.launch().envs(env).pwd(workspace).stdout(listener); - // Configure all servers, skip if all server ids have already been configured. - if (shouldConfig(jfrogHomeTempDir)) { - logIfNoToolProvided(env, listener); - configAllServers(jfLauncher, jfrogBinaryPath, isWindows, run.getParent()); + + /** + * Log if the JFrog CLI binary path doesn't exist in job's environment variable. + * This environment variable exists in one of the following scenarios: + * 1. Declarative Pipeline: A 'jfrog' tool was set + * 2. Scripted Pipeline: Using the "withEnv(["JFROG_BINARY_PATH=${tool 'jfrog-cli'}"])" syntax + * + * @param env - Job's environment variables + * @param listener - Job's logger + */ + private void logIfNoToolProvided(EnvVars env, TaskListener listener) { + if (env.containsKey(JFROG_BINARY_PATH)) { + return; + } + JenkinsBuildInfoLog buildInfoLog = new JenkinsBuildInfoLog(listener); + buildInfoLog.info("A 'jfrog' tool was not set. Using JFrog CLI from the system path."); } - return jfLauncher; - } - /** - * Before we run a 'jf' command for the first time, we want to configure all servers first. - * We know that all servers have already been configured if there is a "jfrog-cli.conf" file in the ".jfrog" home directory. - * - * @param jfrogHomeTempDir - The temp ".jfrog" directory path. - */ - private boolean shouldConfig(FilePath jfrogHomeTempDir) throws IOException, InterruptedException { - List filesList = jfrogHomeTempDir.list(); - for (FilePath file : filesList) { - if (file.getName().contains("jfrog-cli.conf")) { - return false; + /** + * Configure all JFrog relevant environment variables and all servers (if they haven't been configured yet). + * + * @param run running as part of a specific build + * @param env environment variables applicable to this step + * @param launcher a way to start processes + * @param listener a place to send output + * @param workspace a workspace to use for any file operations + * @param jfrogBinaryPath path to jfrog cli binary on the filesystem + * @param isWindows is Windows the applicable OS + * @return launcher applicable to this step. + * @throws InterruptedException if the step is interrupted + * @throws IOException in case of any I/O error, or we failed to run the 'jf' command + */ + public Launcher.ProcStarter setupJFrogEnvironment(Run run, EnvVars env, Launcher launcher, TaskListener listener, FilePath workspace, String jfrogBinaryPath, boolean isWindows) throws IOException, InterruptedException { + JFrogCliConfigEncryption jfrogCliConfigEncryption = run.getAction(JFrogCliConfigEncryption.class); + if (jfrogCliConfigEncryption == null) { + // Set up the config encryption action to allow encrypting the JFrog CLI configuration and make sure we only create one key + jfrogCliConfigEncryption = new JFrogCliConfigEncryption(env); + run.addAction(jfrogCliConfigEncryption); } + FilePath jfrogHomeTempDir = Utils.createAndGetJfrogCliHomeTempDir(workspace, String.valueOf(run.getNumber())); + CliEnvConfigurator.configureCliEnv(env, jfrogHomeTempDir.getRemote(), jfrogCliConfigEncryption); + Launcher.ProcStarter jfLauncher = launcher.launch().envs(env).pwd(workspace).stdout(listener); + // Configure all servers, skip if all server ids have already been configured. + if (shouldConfig(jfrogHomeTempDir)) { + logIfNoToolProvided(env, listener); + configAllServers(jfLauncher, jfrogBinaryPath, isWindows, run.getParent()); + } + return jfLauncher; } - return true; - } - /** - * Locally configure all servers that was configured in the Jenkins UI. - */ - private void configAllServers(Launcher.ProcStarter launcher, String jfrogBinaryPath, boolean isWindows, Job job) throws IOException, InterruptedException { - // Config all servers using the 'jf c add' command. - List jfrogInstances = JFrogPlatformBuilder.getJFrogPlatformInstances(); - if (jfrogInstances != null && jfrogInstances.size() > 0) { - for (JFrogPlatformInstance jfrogPlatformInstance : jfrogInstances) { - // Build 'jf' command - ArgumentListBuilder builder = new ArgumentListBuilder(); - addConfigArguments(builder, jfrogPlatformInstance, jfrogBinaryPath, job); - if (isWindows) { - builder = builder.toWindowsCommand(); - } - // Running 'jf' command - int exitValue = launcher.cmds(builder).join(); - if (exitValue != 0) { - throw new RuntimeException("Running 'jf' command failed with exit code " + exitValue); + /** + * Before we run a 'jf' command for the first time, we want to configure all servers first. + * We know that all servers have already been configured if there is a "jfrog-cli.conf" file in the ".jfrog" home directory. + * + * @param jfrogHomeTempDir - The temp ".jfrog" directory path. + */ + private boolean shouldConfig(FilePath jfrogHomeTempDir) throws IOException, InterruptedException { + List filesList = jfrogHomeTempDir.list(); + for (FilePath file : filesList) { + if (file.getName().contains("jfrog-cli.conf")) { + return false; } } + return true; } - } - private void addConfigArguments(ArgumentListBuilder builder, JFrogPlatformInstance jfrogPlatformInstance, String jfrogBinaryPath, Job job) { - String credentialsId = jfrogPlatformInstance.getCredentialsConfig().getCredentialsId(); - builder.add(jfrogBinaryPath).add("c").add("add").add(jfrogPlatformInstance.getId()); - // Add credentials - StringCredentials accessTokenCredentials = PluginsUtils.accessTokenCredentialsLookup(credentialsId, job); - if (accessTokenCredentials != null) { - builder.addMasked("--access-token=" + accessTokenCredentials.getSecret().getPlainText()); - } else { - Credentials credentials = PluginsUtils.credentialsLookup(credentialsId, job); - builder.add("--user=" + credentials.getUsername()); - builder.addMasked("--password=" + credentials.getPassword()); + /** + * Locally configure all servers that was configured in the Jenkins UI. + */ + private void configAllServers(Launcher.ProcStarter launcher, String jfrogBinaryPath, boolean isWindows, Job job) throws IOException, InterruptedException { + // Config all servers using the 'jf c add' command. + List jfrogInstances = JFrogPlatformBuilder.getJFrogPlatformInstances(); + if (jfrogInstances != null && !jfrogInstances.isEmpty()) { + for (JFrogPlatformInstance jfrogPlatformInstance : jfrogInstances) { + // Build 'jf' command + ArgumentListBuilder builder = new ArgumentListBuilder(); + addConfigArguments(builder, jfrogPlatformInstance, jfrogBinaryPath, job); + if (isWindows) { + builder = builder.toWindowsCommand(); + } + // Running 'jf' command + int exitValue = launcher.cmds(builder).join(); + if (exitValue != 0) { + throw new RuntimeException("Running 'jf' command failed with exit code " + exitValue); + } + } + } } - // Add URLs - builder.add("--url=" + jfrogPlatformInstance.getUrl()); - builder.add("--artifactory-url=" + jfrogPlatformInstance.inferArtifactoryUrl()); - builder.add("--distribution-url=" + jfrogPlatformInstance.inferDistributionUrl()); - builder.add("--xray-url=" + jfrogPlatformInstance.inferXrayUrl()); - builder.add("--interactive=false"); - // The installation process takes place more than once per build, so we will configure the same server ID several times. - builder.add("--overwrite=true"); - } + private void addConfigArguments(ArgumentListBuilder builder, JFrogPlatformInstance jfrogPlatformInstance, String jfrogBinaryPath, Job job) { + String credentialsId = jfrogPlatformInstance.getCredentialsConfig().getCredentialsId(); + builder.add(jfrogBinaryPath).add("c").add("add").add(jfrogPlatformInstance.getId()); + // Add credentials + StringCredentials accessTokenCredentials = PluginsUtils.accessTokenCredentialsLookup(credentialsId, job); + if (accessTokenCredentials != null) { + builder.addMasked("--access-token=" + accessTokenCredentials.getSecret().getPlainText()); + } else { + Credentials credentials = PluginsUtils.credentialsLookup(credentialsId, job); + builder.add("--user=" + credentials.getUsername()); + builder.addMasked("--password=" + credentials.getPassword()); + } + // Add URLs + builder.add("--url=" + jfrogPlatformInstance.getUrl()); + builder.add("--artifactory-url=" + jfrogPlatformInstance.inferArtifactoryUrl()); + builder.add("--distribution-url=" + jfrogPlatformInstance.inferDistributionUrl()); + builder.add("--xray-url=" + jfrogPlatformInstance.inferXrayUrl()); + builder.add("--interactive=false"); + // The installation process takes place more than once per build, so we will configure the same server ID several times. + builder.add("--overwrite=true"); + } + } /** * Add build-info Action if the command is 'jf rt bp' or 'jf rt build-publish'. * @@ -240,7 +242,7 @@ private void addConfigArguments(ArgumentListBuilder builder, JFrogPlatformInstan * @param run - The Jenkins project * @param taskOutputStream - Task's output stream */ - void addBuildInfoActionIfNeeded(Log log, Run run, ByteArrayOutputStream taskOutputStream) { + static void addBuildInfoActionIfNeeded(String[] args, Log log, Run run, ByteArrayOutputStream taskOutputStream) { if (args.length < 2 || !args[0].equals("rt") || !equalsAny(args[1], "bp", "build-publish")) { @@ -276,13 +278,17 @@ void addBuildInfoActionIfNeeded(Log log, Run run, ByteArrayOutputStream ta } } - private void logIllegalBuildPublishOutput(Log log, ByteArrayOutputStream taskOutputStream) { + private static void logIllegalBuildPublishOutput(Log log, ByteArrayOutputStream taskOutputStream) { log.warn("Illegal build-publish output: " + taskOutputStream.toString(StandardCharsets.UTF_8)); } - @Symbol("jf") @Extension - public static final class DescriptorImpl extends BuildStepDescriptor { + public static final class DescriptorImpl extends StepDescriptor { + @Override + public String getFunctionName() { + return "jf"; + } + @Nonnull @Override public String getDisplayName() { @@ -290,8 +296,8 @@ public String getDisplayName() { } @Override - public boolean isApplicable(Class jobType) { - return true; + public Set> getRequiredContext() { + return Set.of(Launcher.class, FilePath.class, TaskListener.class, EnvVars.class); } } } diff --git a/src/test/java/io/jenkins/plugins/jfrog/AddBuildInfoActionTest.java b/src/test/java/io/jenkins/plugins/jfrog/AddBuildInfoActionTest.java index 8d41d977..b480d59f 100644 --- a/src/test/java/io/jenkins/plugins/jfrog/AddBuildInfoActionTest.java +++ b/src/test/java/io/jenkins/plugins/jfrog/AddBuildInfoActionTest.java @@ -83,7 +83,8 @@ public void addBuildInfoActionNegativeTest(String command, String output) throws private void runCliCommand(String command, String output) throws IOException { try (ByteArrayOutputStream taskOutputStream = new ByteArrayOutputStream()) { taskOutputStream.writeBytes(output.getBytes(StandardCharsets.UTF_8)); - new JfStep(command).addBuildInfoActionIfNeeded(new NullLog(), run, taskOutputStream); + JfStep jfStep = new JfStep(command); + JfStep.addBuildInfoActionIfNeeded(jfStep.getArgs(), new NullLog(), run, taskOutputStream); } } } diff --git a/src/test/java/io/jenkins/plugins/jfrog/JfStepTest.java b/src/test/java/io/jenkins/plugins/jfrog/JfStepTest.java index afa4025f..2c9e858f 100644 --- a/src/test/java/io/jenkins/plugins/jfrog/JfStepTest.java +++ b/src/test/java/io/jenkins/plugins/jfrog/JfStepTest.java @@ -8,7 +8,7 @@ import java.util.stream.Stream; -import static io.jenkins.plugins.jfrog.JfStep.getJFrogCLIPath; +import static io.jenkins.plugins.jfrog.JfStep.Execution.getJFrogCLIPath; import static io.jenkins.plugins.jfrog.JfrogInstallation.JFROG_BINARY_PATH; /** diff --git a/src/test/java/io/jenkins/plugins/jfrog/integration/JFrogInstallationITest.java b/src/test/java/io/jenkins/plugins/jfrog/integration/JFrogInstallationITest.java index 79138eac..0dbdfa1d 100644 --- a/src/test/java/io/jenkins/plugins/jfrog/integration/JFrogInstallationITest.java +++ b/src/test/java/io/jenkins/plugins/jfrog/integration/JFrogInstallationITest.java @@ -226,4 +226,15 @@ public void testConfigurationAsCode(JenkinsRule jenkins) throws Exception { assertTrue(StringUtils.containsIgnoreCase(output, "jfrog:")); } } + + @Test + public void testOutput(JenkinsRule jenkins) throws Exception { + setupJenkins(jenkins); + + // Download the latest CLI version from releases.jfrog.io. + configureJfrogCliFromReleases(StringUtils.EMPTY, false); + + // Run pipeline that asserts the output is correct + runPipeline(jenkins, "version_output"); + } } diff --git a/src/test/resources/integration/pipelines/version_output.pipeline b/src/test/resources/integration/pipelines/version_output.pipeline new file mode 100644 index 00000000..14adb51e --- /dev/null +++ b/src/test/resources/integration/pipelines/version_output.pipeline @@ -0,0 +1,21 @@ +pipeline { + agent any + tools { + jfrog '${JFROG_CLI_TOOL_NAME_1}' + } + stages { + stage ('Testing') { + steps { + script { + // Run 'jf -v' with string args to show the installed version of JFrog CLI and check the output. + String version = jf '-v' + assert version.startsWith('jf version') + + // Run 'jf -v' with commands array to show the installed version of JFrog CLI and check the output. + version = jf(['-v']) + assert version.startsWith('jf version') + } + } + } + } +} \ No newline at end of file