diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..1142b20 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +@jenkinsci/ssh-steps-plugin-developers diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6415b11 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 8d567bb..0d0b1c9 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,3 +1 @@ _extends: .github -tag-template: ssh-steps-$NEXT_PATCH_VERSION -version-template: $MAJOR.$MINOR.$PATCH diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..f770894 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,59 @@ +# Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins + +name: cd +on: + workflow_dispatch: + check_run: + types: + - completed + +jobs: + validate: + runs-on: ubuntu-latest + outputs: + should_release: ${{ steps.verify-ci-status.outputs.result == 'success' && steps.interesting-categories.outputs.interesting == 'true' }} + steps: + - name: Verify CI status + uses: jenkins-infra/verify-ci-status-action@v1.2.0 + id: verify-ci-status + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + output_result: true + + - name: Release Drafter + uses: release-drafter/release-drafter@v5 + if: steps.verify-ci-status.outputs.result == 'success' + with: + name: next + tag: next + version: next + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check interesting categories + uses: jenkins-infra/interesting-category-action@v1.0.0 + id: interesting-categories + if: steps.verify-ci-status.outputs.result == 'success' + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + release: + runs-on: ubuntu-latest + needs: [ validate ] + if: needs.validate.outputs.should_release == 'true' + steps: + - name: Check out + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up JDK 8 + uses: actions/setup-java@v3 + with: + distribution: "adopt" + java-version: 8 + - name: Release + uses: jenkins-infra/jenkins-maven-cd-action@v1.2.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml new file mode 100644 index 0000000..fc14821 --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,9 @@ + + + git-changelist-maven-extension + io.jenkins.tools.incrementals + 1.3 + + diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 0000000..2a2667e --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1 @@ +-Djava.awt.headless=true diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000..f7daf60 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,3 @@ +-Pconsume-incrementals +-Pmight-produce-incrementals +-Dchangelist.format=%d.v%s diff --git a/pom.xml b/pom.xml index e103d12..d57241d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,22 +1,28 @@ - + 4.0.0 org.jenkins-ci.plugins plugin - 3.55 + 4.40 ssh-steps - 2.0.1-SNAPSHOT + ${revision}.${changelist} hpi SSH Pipeline Steps - SSH Pipeline Steps - https://github.com/jenkinsci/ssh-steps-plugin 2018 - - Cerner Corporation - https://www.cerner.com/ - + https://github.com/jenkinsci/${project.artifactId}-plugin + + 2.0 + 999999-SNAPSHOT + 8 + 2.332.2 + jenkinsci/${project.artifactId}-plugin + 2.10.1 + 1.18.24 + 3.22.0 + Apache License, Version 2.0 @@ -28,45 +34,45 @@ nrayapati Naresh Rayapati - Cerner Corporation - https://www.cerner.com/ - - scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git - scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git - HEAD - https://github.com/jenkinsci/${project.artifactId}-plugin + + + scm:git:https://github.com/${gitHubRepo} + scm:git:https://github.com/${gitHubRepo} + ${scmTag} + https://github.com/${gitHubRepo} - + + repo.jenkins-ci.org - https://repo.jenkins-ci.org/releases + https://repo.jenkins-ci.org/public/ - - maven.jenkins-ci.org - https://repo.jenkins-ci.org/snapshots - - - - 8 - 2.121.1 - 2.49 - 2.19 - 2.4.11 - 2.10.1 - 1.18.8 - - 2.23.2 - 1.10.19 - 1.7.4 - 3.12.2 - + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + + + bom-2.332.x + io.jenkins.tools.bom + import + pom + 1342.v729ca_3818e88 + + + + org.jenkins-ci.plugins.workflow workflow-step-api - ${workflow-step-api-version} org.projectlombok @@ -74,12 +80,6 @@ ${lombok.version} provided - - org.codehaus.groovy - groovy-all - ${groovy.version} - provided - org.hidetake groovy-ssh @@ -98,67 +98,20 @@ org.mockito - mockito-all - ${mockito.version} - test - - - org.powermock - powermock-module-junit4 - ${powermock.version} + mockito-inline test - - - junit - junit - - - org.powermock - powermock-api-mockito - ${powermock.version} + net.java.dev.jna + jna-platform + 5.8.0 test - - - mockito-core - org.mockito - - junit junit test - - com.github.tomakehurst - wiremock - ${wiremock.version} - test - - - jetty-server - org.eclipse.jetty - - - jetty-servlets - org.eclipse.jetty - - - jetty-servlet - org.eclipse.jetty - - - jetty-webapp - org.eclipse.jetty - - - commons-codec - commons-codec - - - org.assertj assertj-core @@ -166,18 +119,6 @@ test - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - diff --git a/src/main/resources/index.jelly b/src/main/resources/index.jelly new file mode 100644 index 0000000..093acfb --- /dev/null +++ b/src/main/resources/index.jelly @@ -0,0 +1,4 @@ + +
+ Jenkins pipeline steps which provides SSH facilities such as command execution or file transfer for continuous delivery. +
diff --git a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/BaseTest.java b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/BaseTest.java new file mode 100644 index 0000000..1bef193 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/BaseTest.java @@ -0,0 +1,73 @@ +package org.jenkinsci.plugins.sshsteps.steps; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +import hudson.EnvVars; +import hudson.Launcher; +import hudson.model.Run; +import hudson.model.TaskListener; +import java.io.IOException; +import java.io.PrintStream; +import org.jenkinsci.plugins.sshsteps.SSHService; +import org.jenkinsci.plugins.sshsteps.util.TestVirtualChannel; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.junit.After; +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +/** + * Base Test Class. + * + * @author Naresh Rayapati + */ +public class BaseTest { + + @Mock + TaskListener taskListenerMock; + @Mock + Run runMock; + @Mock + EnvVars envVarsMock; + @Mock + PrintStream printStreamMock; + @Mock + SSHService sshServiceMock; + @Mock + StepContext contextMock; + @Mock + Launcher launcherMock; + + private AutoCloseable closeable; + private MockedStatic sshService; + + @Before + public void setUpBase() throws IOException, InterruptedException { + + closeable = MockitoAnnotations.openMocks(this); + + when(runMock.getCauses()).thenReturn(null); + when(taskListenerMock.getLogger()).thenReturn(printStreamMock); + doNothing().when(printStreamMock).println(); + when(launcherMock.getChannel()).thenReturn(new TestVirtualChannel()); + + sshService = Mockito.mockStatic(SSHService.class); + sshService.when(() -> SSHService.create(any(), anyBoolean(), anyBoolean(), any())).thenReturn(sshServiceMock); + + when(contextMock.get(Run.class)).thenReturn(runMock); + when(contextMock.get(TaskListener.class)).thenReturn(taskListenerMock); + when(contextMock.get(EnvVars.class)).thenReturn(envVarsMock); + when(contextMock.get(Launcher.class)).thenReturn(launcherMock); + } + + @After + public void tearUpBase() throws Exception { + sshService.close(); + closeable.close(); + } +} diff --git a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/CommandStepTest.java b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/CommandStepTest.java index 6cea436..8ffa0f2 100644 --- a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/CommandStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/CommandStepTest.java @@ -1,8 +1,8 @@ package org.jenkinsci.plugins.sshsteps.steps; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -21,54 +21,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; /** * Unit test cases for CommandStep class. * * @author Naresh Rayapati */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({CommandStepTest.class, SSHService.class}) -public class CommandStepTest { - - @Mock - TaskListener taskListenerMock; - @Mock - Run runMock; - @Mock - EnvVars envVarsMock; - @Mock - PrintStream printStreamMock; - @Mock - SSHService sshServiceMock; - @Mock - StepContext contextMock; - @Mock - Launcher launcherMock; +public class CommandStepTest extends BaseTest { CommandStep.Execution stepExecution; - @Before - public void setup() throws IOException, InterruptedException { - - when(runMock.getCauses()).thenReturn(null); - when(taskListenerMock.getLogger()).thenReturn(printStreamMock); - doNothing().when(printStreamMock).println(); - when(launcherMock.getChannel()).thenReturn(new TestVirtualChannel()); - - PowerMockito.mockStatic(SSHService.class); - when(SSHService.create(any(), anyBoolean(), anyBoolean(), any())).thenReturn(sshServiceMock); - - when(contextMock.get(Run.class)).thenReturn(runMock); - when(contextMock.get(TaskListener.class)).thenReturn(taskListenerMock); - when(contextMock.get(EnvVars.class)).thenReturn(envVarsMock); - when(contextMock.get(Launcher.class)).thenReturn(launcherMock); - - } - @Test public void testWithEmptyCommandThrowsIllegalArgumentException() throws Exception { final CommandStep step = new CommandStep(""); diff --git a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/GetStepTest.java b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/GetStepTest.java index 71d42a1..d1ac21a 100644 --- a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/GetStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/GetStepTest.java @@ -1,8 +1,8 @@ package org.jenkinsci.plugins.sshsteps.steps; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -22,37 +22,18 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; /** * Unit test cases for GetStep class. * * @author Naresh Rayapati */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({GetStepTest.class, SSHService.class, FilePath.class}) -public class GetStepTest { +public class GetStepTest extends BaseTest { final String path = "test.sh"; final String filterBy = "name"; final String filterRegex = null; - @Mock - TaskListener taskListenerMock; - @Mock - Run runMock; - @Mock - EnvVars envVarsMock; - @Mock - PrintStream printStreamMock; - @Mock - SSHService sshServiceMock; - @Mock - StepContext contextMock; - @Mock - Launcher launcherMock; @Mock FilePath filePathMock; @@ -61,23 +42,11 @@ public class GetStepTest { @Before public void setup() throws IOException, InterruptedException { - when(runMock.getCauses()).thenReturn(null); - when(taskListenerMock.getLogger()).thenReturn(printStreamMock); - doNothing().when(printStreamMock).println(); - when(launcherMock.getChannel()).thenReturn(new TestVirtualChannel()); - - PowerMockito.mockStatic(SSHService.class); - when(SSHService.create(any(), anyBoolean(), anyBoolean(), any())).thenReturn(sshServiceMock); - when(filePathMock.child(any())).thenReturn(filePathMock); when(filePathMock.exists()).thenReturn(true); when(filePathMock.isDirectory()).thenReturn(false); when(filePathMock.getRemote()).thenReturn(path); - when(contextMock.get(Run.class)).thenReturn(runMock); - when(contextMock.get(TaskListener.class)).thenReturn(taskListenerMock); - when(contextMock.get(EnvVars.class)).thenReturn(envVarsMock); - when(contextMock.get(Launcher.class)).thenReturn(launcherMock); when(contextMock.get(FilePath.class)).thenReturn(filePathMock); } diff --git a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/PutStepTest.java b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/PutStepTest.java index a10328b..5949577 100644 --- a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/PutStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/PutStepTest.java @@ -1,8 +1,8 @@ package org.jenkinsci.plugins.sshsteps.steps; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -22,37 +22,18 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; /** * Unit test cases for PutStep class. * * @author Naresh Rayapati */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({PutStepTest.class, SSHService.class, FilePath.class}) -public class PutStepTest { +public class PutStepTest extends BaseTest { final String path = "test.sh"; final String filterBy = "name"; final String filterRegex = null; - @Mock - TaskListener taskListenerMock; - @Mock - Run runMock; - @Mock - EnvVars envVarsMock; - @Mock - PrintStream printStreamMock; - @Mock - SSHService sshServiceMock; - @Mock - StepContext contextMock; - @Mock - Launcher launcherMock; @Mock FilePath filePathMock; @@ -61,23 +42,11 @@ public class PutStepTest { @Before public void setup() throws IOException, InterruptedException { - when(runMock.getCauses()).thenReturn(null); - when(taskListenerMock.getLogger()).thenReturn(printStreamMock); - doNothing().when(printStreamMock).println(); - when(launcherMock.getChannel()).thenReturn(new TestVirtualChannel()); - - PowerMockito.mockStatic(SSHService.class); - when(SSHService.create(any(), anyBoolean(), anyBoolean(), any())).thenReturn(sshServiceMock); - when(filePathMock.child(any())).thenReturn(filePathMock); when(filePathMock.exists()).thenReturn(true); when(filePathMock.isDirectory()).thenReturn(false); when(filePathMock.getRemote()).thenReturn(path); - when(contextMock.get(Run.class)).thenReturn(runMock); - when(contextMock.get(TaskListener.class)).thenReturn(taskListenerMock); - when(contextMock.get(EnvVars.class)).thenReturn(envVarsMock); - when(contextMock.get(Launcher.class)).thenReturn(launcherMock); when(contextMock.get(FilePath.class)).thenReturn(filePathMock); } diff --git a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/RemoveStepTest.java b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/RemoveStepTest.java index 5b36ae9..ad6c9f0 100644 --- a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/RemoveStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/RemoveStepTest.java @@ -1,8 +1,8 @@ package org.jenkinsci.plugins.sshsteps.steps; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -22,35 +22,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; /** * Unit test cases for RemoveStep class. * * @author Naresh Rayapati */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({RemoveStepTest.class, SSHService.class, FilePath.class}) -public class RemoveStepTest { +public class RemoveStepTest extends BaseTest { final String path = "test.sh"; - @Mock - TaskListener taskListenerMock; - @Mock - Run runMock; - @Mock - EnvVars envVarsMock; - @Mock - PrintStream printStreamMock; - @Mock - SSHService sshServiceMock; - @Mock - StepContext contextMock; - @Mock - Launcher launcherMock; @Mock FilePath filePathMock; @@ -59,23 +40,11 @@ public class RemoveStepTest { @Before public void setup() throws IOException, InterruptedException { - when(runMock.getCauses()).thenReturn(null); - when(taskListenerMock.getLogger()).thenReturn(printStreamMock); - doNothing().when(printStreamMock).println(); - when(launcherMock.getChannel()).thenReturn(new TestVirtualChannel()); - - PowerMockito.mockStatic(SSHService.class); - when(SSHService.create(any(), anyBoolean(), anyBoolean(), any())).thenReturn(sshServiceMock); - when(filePathMock.child(any())).thenReturn(filePathMock); when(filePathMock.exists()).thenReturn(true); when(filePathMock.isDirectory()).thenReturn(false); when(filePathMock.getRemote()).thenReturn(path); - when(contextMock.get(Run.class)).thenReturn(runMock); - when(contextMock.get(TaskListener.class)).thenReturn(taskListenerMock); - when(contextMock.get(EnvVars.class)).thenReturn(envVarsMock); - when(contextMock.get(Launcher.class)).thenReturn(launcherMock); when(contextMock.get(FilePath.class)).thenReturn(filePathMock); } diff --git a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/ScriptStepTest.java b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/ScriptStepTest.java index d46e152..6ee415c 100644 --- a/src/test/java/org/jenkinsci/plugins/sshsteps/steps/ScriptStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/sshsteps/steps/ScriptStepTest.java @@ -1,8 +1,8 @@ package org.jenkinsci.plugins.sshsteps.steps; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -22,35 +22,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; /** * Unit test cases for ScriptStep class. * * @author Naresh Rayapati */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({ScriptStepTest.class, SSHService.class, FilePath.class}) -public class ScriptStepTest { +public class ScriptStepTest extends BaseTest { final String scriptName = "test.sh"; - @Mock - TaskListener taskListenerMock; - @Mock - Run runMock; - @Mock - EnvVars envVarsMock; - @Mock - PrintStream printStreamMock; - @Mock - SSHService sshServiceMock; - @Mock - StepContext contextMock; - @Mock - Launcher launcherMock; @Mock FilePath filePathMock; @@ -59,23 +40,11 @@ public class ScriptStepTest { @Before public void setup() throws IOException, InterruptedException { - when(runMock.getCauses()).thenReturn(null); - when(taskListenerMock.getLogger()).thenReturn(printStreamMock); - doNothing().when(printStreamMock).println(); - when(launcherMock.getChannel()).thenReturn(new TestVirtualChannel()); - - PowerMockito.mockStatic(SSHService.class); - when(SSHService.create(any(), anyBoolean(), anyBoolean(), any())).thenReturn(sshServiceMock); - when(filePathMock.child(any())).thenReturn(filePathMock); when(filePathMock.exists()).thenReturn(true); when(filePathMock.isDirectory()).thenReturn(false); when(filePathMock.getRemote()).thenReturn(scriptName); - when(contextMock.get(Run.class)).thenReturn(runMock); - when(contextMock.get(TaskListener.class)).thenReturn(taskListenerMock); - when(contextMock.get(EnvVars.class)).thenReturn(envVarsMock); - when(contextMock.get(Launcher.class)).thenReturn(launcherMock); when(contextMock.get(FilePath.class)).thenReturn(filePathMock); }