├── .github ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── release-drafter.yml │ └── test.yml ├── .gitignore ├── Jenkinsfile ├── LICENSE.txt ├── README.md ├── RELEASE.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── grapeConfig.xml └── src ├── main └── groovy │ └── com │ └── lesfurets │ └── jenkins │ └── unit │ ├── BasePipelineTest.groovy │ ├── BaseRegressionTest.groovy │ ├── DockerMock.groovy │ ├── InterceptingGCL.groovy │ ├── LibClassLoader.groovy │ ├── MethodCall.groovy │ ├── MethodSignature.groovy │ ├── MockPipelineScript.groovy │ ├── PipelineTestHelper.groovy │ ├── RegressionTest.groovy │ ├── RegressionTestHelper.groovy │ ├── VerificationException.groovy │ ├── cps │ ├── BasePipelineTestCPS.groovy │ ├── BaseRegressionTestCPS.groovy │ ├── MockClosure.groovy │ ├── MockPipelineScriptCPS.groovy │ └── PipelineTestHelperCPS.groovy │ ├── declarative │ ├── AgentDeclaration.groovy │ ├── AllOfDeclaration.groovy │ ├── AnyOfDeclaration.groovy │ ├── ChangeRequestDeclaration.groovy │ ├── ComparatorEnum.groovy │ ├── DeclarativePipeline.groovy │ ├── DeclarativePipelineTest.groovy │ ├── GenericPipelineDeclaration.groovy │ ├── NotDeclaration.groovy │ ├── ObjectUtils.groovy │ ├── ParallelDeclaration.groovy │ ├── ParametersDeclaration.groovy │ ├── PostDeclaration.groovy │ ├── StageDeclaration.groovy │ ├── WhenDeclaration.groovy │ ├── agent │ │ ├── DockerAgentDeclaration.groovy │ │ ├── DockerfileAgentDeclaration.groovy │ │ └── KubernetesAgentDeclaration.groovy │ └── kubernetes │ │ ├── ContainerLivenessProbeDeclaration.groovy │ │ ├── ContainerTemplateDeclaration.groovy │ │ ├── PodTemplateDeclaration.groovy │ │ ├── PortMappingDeclaration.groovy │ │ ├── TemplateEnvVarDeclaration.groovy │ │ └── WorkspaceVolumeDeclaration.groovy │ └── global │ └── lib │ ├── GitSource.groovy │ ├── Library.groovy │ ├── LibraryAnnotationTransformer.groovy │ ├── LibraryConfiguration.groovy │ ├── LibraryLoader.groovy │ ├── LibraryRecord.groovy │ ├── LocalSource.groovy │ ├── ProjectSource.groovy │ └── SourceRetriever.groovy └── test ├── groovy └── com │ ├── TestCatchError.groovy │ └── lesfurets │ └── jenkins │ ├── TestAddCredential.groovy │ ├── TestAddEnvVar.groovy │ ├── TestAddParam.groovy │ ├── TestCustomMethodJob.groovy │ ├── TestCustomMethodJobCPS.groovy │ ├── TestDeclarativeImmutableParams.groovy │ ├── TestExampleJob.groovy │ ├── TestExampleJobCPS.groovy │ ├── TestFailingJobs.groovy │ ├── TestHelperInitialization.groovy │ ├── TestHelperSingleton.groovy │ ├── TestInlineScript.groovy │ ├── TestInterceptingGCL.groovy │ ├── TestInterceptingGCLLazyLoadLibClasses.groovy │ ├── TestLibraryResourceStep.groovy │ ├── TestOneArgumentJob.groovy │ ├── TestParallelJob.groovy │ ├── TestParallelJobCPS.groovy │ ├── TestParametersJob.groovy │ ├── TestRegisterOriginalMethodCallArgs.groovy │ ├── TestRegression.groovy │ ├── TestRegressionGlobalVar.groovy │ ├── TestSerialization.groovy │ ├── TestSerializationCPS.groovy │ ├── TestSharedLibraryAccessibleParams.groovy │ ├── TestSharedLibraryEnvVariable.groovy │ ├── TestSharedLibraryWithLocalSourceRetriever.groovy │ ├── TestSharedLibraryWithLocalSourceRetrieverCPS.groovy │ ├── TestSharedLibraryWithProjectSourceRetriever.groovy │ ├── TestSharedLibraryWithProjectSourceRetrieverCPS.groovy │ ├── TestUtilsLib.groovy │ ├── TestUtilsLibCPS.groovy │ ├── TestWithCredentialsAndParametersJob.groovy │ ├── TestWithCredentialsJob.groovy │ └── unit │ ├── BasePipelineTestTest.groovy │ ├── CallStackDumpTest.groovy │ ├── PipelineTestHelperTest.groovy │ ├── TestDockerMock.groovy │ ├── VerifyTest.groovy │ └── declarative │ ├── TestDeclaraticeWithCredentials.groovy │ ├── TestDeclarativePipeline.groovy │ ├── TestDockerAgentInStep.groovy │ └── TestMockLocalFunction.groovy ├── java └── com │ └── lesfurets │ └── jenkins │ └── TestPipelineJava.java ├── jenkins ├── jenkinsfiles │ ├── AgentEmptyLabel_Jenkinsfile │ ├── AgentParam_Jenkinsfile │ ├── AgentStageNoSteps_Jenkinsfile │ ├── Agent_Jenkinsfile │ ├── Agent_bindings_Jenkinsfile │ ├── Agent_env_Jenkinsfile │ ├── AllOf_Jenkinsfile │ ├── AnyOf_Jenkinsfile │ ├── Branch_Jenkinsfile │ ├── BuildStatus_Failure_Jenkinsfile │ ├── BuildStatus_Success_Jenkinsfile │ ├── ChangeRequest_Jenkinsfile │ ├── ComplexStages_Jenkinsfile │ ├── Credentials_Jenkinsfile │ ├── Declarative_Jenkinsfile │ ├── Docker_Jenkinsfile │ ├── Docker_agentInStep_JenkinsFile │ ├── Dockerfile_Agent_Default_Jenkinsfile │ ├── Dockerfile_Agent_Only_Filename_JenkinsFile │ ├── Dockerfile_agent_JenkinsFile │ ├── Environment_Jenkinsfile │ ├── Kubernetes_Agent_Jenkinsfile │ ├── Kubernetes_Default_Jenkinsfile │ ├── Kubernetes_Map_Agent_Jenkinsfile │ ├── Mock_existing_function_Jenkinsfile │ ├── Mock_existing_function_Jenkinsfile_params │ ├── Nested_AllOf_And_AnyOf_Jenkinsfile │ ├── Nested_AnyOf_And_AllOf_Jenkinsfile │ ├── Nested_BeforeAgent_Jenkinsfile │ ├── Non_Valid_Jenkinsfile │ ├── Parallel_Jenkinsfile │ ├── Parallel_NestedStages_Jenkinsfile │ ├── Parallel_When_Jenkinsfile │ ├── Params_Jenkinsfile │ ├── StageAndSteps_Jenkinsfile │ ├── StageFailed_Jenkinsfile │ ├── Tag_Jenkinsfile │ ├── ThisScope_Jenkinsfile │ ├── WithEnvEquals_Jenkinsfile │ ├── WithEnv_Jenkinsfile │ ├── not_Jenkinsfile │ └── withCredentials_Jenkinsfile ├── job │ ├── callStackDump.jenkins │ ├── customMethod.jenkins │ ├── customMethodWithArguments.jenkins │ ├── exampleJob.jenkins │ ├── globalVar.jenkins │ ├── immutableMapArgs.jenkins │ ├── library │ │ ├── cross_class │ │ │ ├── test_annotation.jenkins │ │ │ ├── test_dynamic.jenkins │ │ │ └── test_implicit.jenkins │ │ ├── cross_class_lazy_load │ │ │ └── test_var_with_lib_class_arg.jenkins │ │ ├── cross_class_pre_loaded │ │ │ ├── test_annotation.jenkins │ │ │ ├── test_dynamic.jenkins │ │ │ └── test_implicit.jenkins │ │ ├── cross_class_with_pipeline_ref │ │ │ ├── test_annotation.jenkins │ │ │ ├── test_dynamic.jenkins │ │ │ └── test_implicit.jenkins │ │ ├── cross_library │ │ │ ├── test_cross_class_annotation.jenkins │ │ │ ├── test_cross_class_dynamic.jenkins │ │ │ └── test_cross_class_implicit.jenkins │ │ ├── cross_vars │ │ │ ├── test_annotation.jenkins │ │ │ ├── test_dynamic.jenkins │ │ │ └── test_implicit.jenkins │ │ ├── libraryJob.jenkins │ │ ├── libraryJob_dynamic_map.jenkins │ │ ├── libraryJob_feature.jenkins │ │ ├── libraryJob_feature2.jenkins │ │ ├── libraryJob_implicit.jenkins │ │ ├── libraryJob_inline_library.jenkins │ │ ├── libraryJob_master.jenkins │ │ ├── params_not_accessible.jenkins │ │ ├── test_lib_call_shell_annotation.jenkins │ │ ├── test_lib_call_shell_dynamic.jenkins │ │ ├── test_lib_call_with_null.jenkins │ │ ├── test_lib_var_not_defined_in_env.jenkins │ │ ├── test_libraryResource_as_base64.jenkins │ │ ├── test_libraryResource_with_encoding.jenkins │ │ ├── test_libraryResource_with_string.jenkins │ │ ├── test_libraryResource_without_encoding.jenkins │ │ ├── test_params_immutable_declarative.jenkins │ │ └── test_params_not_defined_in_env.jenkins │ ├── parallelJob.jenkins │ ├── parameters.jenkins │ ├── serialize.jenkins │ ├── serializeCPS.jenkins │ ├── shouldFail │ │ ├── forEach.jenkins │ │ └── nonCpsCallingCps.jenkins │ ├── verify.jenkins │ ├── withCredentials.jenkins │ └── withCredentialsAndParameters.jenkins └── lib │ ├── properties.jenkins │ └── utils.jenkins └── resources ├── callstacks ├── TestJenkinsFile_develop.txt ├── TestJenkinsFile_feature_.txt ├── TestJenkinsFile_master.txt ├── TestOneArgumentJob_should_run_script_with_one_argument.txt ├── TestParametersJob_parameters.txt ├── TestRegressionGlobalVar_globalVar.txt ├── TestRegression_example.txt ├── TestWithCredentialsAndParametersJob_withCredentialsAndParameters.txt └── TestWithCredentialsJob_withCredentials.txt ├── libs ├── commons@feature │ ├── resources │ │ └── net │ │ │ └── courtanet │ │ │ └── jenkins │ │ │ ├── icon.png │ │ │ ├── plaintext.iso-8859-1.txt │ │ │ └── plaintext.utf8.txt │ ├── src │ │ └── net │ │ │ └── courtanet │ │ │ └── jenkins │ │ │ └── Utils2.groovy │ └── vars │ │ ├── greetings.groovy │ │ ├── helloMessage.groovy │ │ ├── oneArg.groovy │ │ └── sayHello.groovy ├── commons@master │ ├── resources │ │ └── net │ │ │ └── courtanet │ │ │ └── jenkins │ │ │ └── pom.xml │ ├── src │ │ └── net │ │ │ └── courtanet │ │ │ └── jenkins │ │ │ └── Utils.groovy │ └── vars │ │ ├── acme.groovy │ │ └── sayHello.groovy ├── env_var_not_defined │ └── vars │ │ └── envHelper.groovy ├── params_not_accessible │ └── src │ │ └── org │ │ └── test │ │ └── LibClass.groovy ├── test_cross_class_as_var_arg_1 │ ├── src │ │ └── org │ │ │ └── test │ │ │ └── Monster1.groovy │ └── vars │ │ └── monster1.groovy ├── test_cross_class_as_var_arg_2 │ ├── src │ │ └── org │ │ │ └── test │ │ │ └── extra │ │ │ └── Monster2.groovy │ └── vars │ │ └── monster2.groovy ├── test_cross_class_usage │ └── src │ │ └── org │ │ └── test │ │ ├── ClassA.groovy │ │ ├── ClassAB.groovy │ │ └── ClassB.groovy └── test_cross_vars_usage │ ├── src │ └── org │ │ └── test │ │ └── LaClass.groovy │ └── vars │ ├── methodA.groovy │ ├── methodAB.groovy │ └── methodB.groovy └── test-pom.xml /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: gradle 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # See https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 2 | _extends: jenkinsci/.github 3 | version-template: $MAJOR.$MINOR 4 | tag-template: v$NEXT_MINOR_VERSION 5 | name-template: $NEXT_MINOR_VERSION 6 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 2 | 3 | name: Release Drafter 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into the default branch 15 | - uses: release-drafter/release-drafter@v5 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | test: 11 | name: macos-17 12 | runs-on: macos-latest 13 | steps: 14 | - name: Setup Java 15 | uses: actions/setup-java@v1 16 | with: 17 | java-version: 17 18 | - name: Checkout 19 | uses: actions/checkout@v2 20 | - name: Run Tests 21 | run: ./gradlew --no-daemon cleanTest build 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | target 3 | .idea 4 | build 5 | .gradle 6 | *.swp 7 | out 8 | .DS_store 9 | .classpath 10 | .project 11 | .settings/ 12 | bin/ -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | buildPluginWithGradle( 2 | configurations: [ 3 | [platform: 'linux', jdk: '17'], 4 | [platform: 'windows', jdk: '17'], 5 | ], 6 | ) 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Courtanet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Procedure 2 | 3 | ## Pre-Requirements 4 | 5 | In order to release a new version you need a `jenkins.io` account, push rights to this 6 | repository and access to Jenkins' JFrog artifactory server. See the [Jenkins plugin 7 | adoption procedure][jenkins-adopt-a-plugin]. 8 | 9 | ## Overview 10 | 11 | In short, the release procedure could described with the following steps: 12 | 13 | 1. Update the version in `gradle.properties` and create a new commit 14 | 2. Make a new tag 15 | 3. Build and publish artifacts to the [Jenkins plugin repository][jenkins-plugin-repo]. 16 | 4. Update the version in `gradle.properties` for the next development cycle 17 | 5. Add release notes to GitHub 18 | 19 | **NOTE:** repo.jenkins-ci.org might have a delay (1-2d) in publishing artifacts to public, 20 | so mark new releases as `pre-release`. Once artifacts are available, the `pre-release` 21 | label can be removed. 22 | 23 | ## Tools 24 | 25 | To automate the above steps, JenkinsPipelineUnit uses a variety of Gradle plugins and 26 | GitHub actions. 27 | 28 | ### Gradle plugins 29 | 30 | #### net.researchgate.release 31 | 32 | This plugin is used to prepare new releases. This Gradle plugin automatically creates a 33 | new commit with the updated release version, makes a new release tag, and then prepares 34 | the repository for the next development cycle. 35 | 36 | #### com.jfrog.artifactory 37 | 38 | Needed to publish artifacts to the repo.jenkins-ci.org/releases maven repository. 39 | 40 | ### GitHub Actions 41 | 42 | There is a [release-drafter][release-drafter] GitHub actions script to prepare release 43 | notes based on issues and PRs which were made to the main branch since the last release. 44 | 45 | ## Example 46 | 47 | Let's say current version is `1.6`, new version is `1.7`, and the next development version 48 | is `1.8-SNAPSHOT`. 49 | 50 | * Checkout release branch 51 | 52 | ```bash 53 | git fetch 54 | git checkout -B master origin/master 55 | ``` 56 | 57 | * Create release: 58 | 59 | ``` 60 | ./gradlew release 61 | # You will be asked for the new version, and new snapshot version 62 | # (just press enter to use default values) 63 | 64 | ``` 65 | * Checkout release tag 66 | 67 | ```bash 68 | git checkout v1.7 69 | ``` 70 | 71 | * Publish artifacts 72 | 73 | ```bash 74 | # create ~/.gradle/gradle.properties with the following content: 75 | # artifactory_user=jenkins.io_username 76 | # artifactory_password=s3cr3t 77 | 78 | ./gradlew artifactoryPublish 79 | ``` 80 | 81 | * Publish new release notes at https://github.com/jenkinsci/JenkinsPipelineUnit/releases 82 | 83 | 84 | [jenkins-adopt-a-plugin]: https://www.jenkins.io/doc/developer/plugin-governance/adopt-a-plugin/ 85 | [jenkins-plugin-repo]: https://repo.jenkins-ci.org/artifactory/releases/com/lesfurets/jenkins-pipeline-unit/ 86 | [release-drafter]: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 87 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # dummy properties 2 | artifactory_user=deployment 3 | artifactory_password=deployment123 4 | version=1.26 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/JenkinsPipelineUnit/18fbbb546c3dba7faf1da9f1bbfe159ba7e599c1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /grapeConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/BaseRegressionTest.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | abstract class BaseRegressionTest extends BasePipelineTest implements RegressionTest { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/DockerMock.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | 4 | @SuppressWarnings(['EmptyMethod', 'MethodReturnTypeRequired', 'UnusedMethodParameter']) 5 | class DockerMock implements Serializable { 6 | class Container implements Serializable { 7 | String id 8 | 9 | Container(String id = 'mock-container') { 10 | this.id = id 11 | } 12 | 13 | def port() { 14 | return '1234' 15 | } 16 | 17 | def stop() {} 18 | } 19 | 20 | class Image implements Serializable { 21 | String id 22 | String tagname 23 | 24 | Image(String id) { 25 | this.id = id 26 | this.tagname = 'latest' 27 | } 28 | 29 | def imageName() { 30 | return id 31 | } 32 | 33 | def inside(String args = '', Closure body) { 34 | return body(new Container()) 35 | } 36 | 37 | def pull() {} 38 | 39 | def push(String tagname = '') { 40 | if (tagname) { 41 | tag(tagname) 42 | } 43 | } 44 | 45 | def run(String args = '', String command = '') { 46 | return new Container() 47 | } 48 | 49 | def tag(String tagname = '') { 50 | this.tagname = tagname 51 | } 52 | 53 | def withRun(String args = '', String command = '', Closure body) { 54 | return body(new Container()) 55 | } 56 | } 57 | 58 | Image build(String image, String args = '') { 59 | return new Image(image) 60 | } 61 | 62 | Image image(String id) { 63 | return new Image(id) 64 | } 65 | 66 | void withRegistry(String url, String credentialsId = '', Closure body) { 67 | body() 68 | } 69 | 70 | void withServer(String uri, String credentialsId = '', Closure body) { 71 | body() 72 | } 73 | 74 | void withTool(String toolName, Closure body) { 75 | body() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/LibClassLoader.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | import org.apache.commons.lang3.reflect.ConstructorUtils; 4 | import org.apache.commons.lang3.reflect.MethodUtils; 5 | 6 | /** 7 | * Kind of proxy object to create instances of library's classes 8 | * 9 | * Copied from https://github.com/jenkinsci/workflow-cps-global-lib-plugin/blob/master/src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryStep.java 10 | */ 11 | class LibClassLoader extends GroovyObjectSupport { 12 | private String className 13 | private PipelineTestHelper helper 14 | Class loadedClass 15 | 16 | LibClassLoader(helper, String className){ 17 | this.helper = helper 18 | this.className = className 19 | this.loadedClass = null 20 | } 21 | 22 | LibClassLoader(helper, String className, loadedClass){ 23 | this.helper = helper 24 | this.className = className 25 | this.loadedClass = loadedClass 26 | } 27 | 28 | @Override 29 | Object getProperty(String property) { 30 | 31 | if(loadedClass) { 32 | return loadedClass.getProperties()[property] 33 | } 34 | 35 | if(!this.className) { 36 | return new LibClassLoader(this.helper, property) 37 | } 38 | 39 | if(property =~ /^[A-Z].*/) { 40 | 41 | def gcl = this.helper.getLibLoader().getGroovyClassLoader() 42 | loadedClass = gcl.loadClass( (String) "${this.className}.${property}") 43 | return new LibClassLoader(this.helper, "${this.className}.${property}", loadedClass) 44 | } else { 45 | return new LibClassLoader(this.helper, "${this.className}.${property}") 46 | } 47 | } 48 | 49 | @Override 50 | Object invokeMethod(String name, Object _args) { 51 | Object[] args = _args as Object[] 52 | if(loadedClass) { 53 | if (name.equals("new")) { 54 | return ConstructorUtils.invokeConstructor(loadedClass, args); 55 | } else { 56 | return MethodUtils.invokeStaticMethod(loadedClass, name, args); 57 | } 58 | } 59 | 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/MethodSignature.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | import static org.codehaus.groovy.runtime.MetaClassHelper.isAssignableFrom 4 | 5 | import groovy.transform.CompileStatic 6 | 7 | @CompileStatic 8 | class MethodSignature { 9 | String name 10 | Class[] args 11 | 12 | static MethodSignature method(String name, Class... args = []) { 13 | return new MethodSignature(name, args) 14 | } 15 | 16 | MethodSignature(String name, Class[] args) { 17 | this.name = name 18 | this.args = args 19 | } 20 | 21 | String argsToString() { 22 | return args.collect { Class it -> 23 | if (it != null && Closure.isAssignableFrom(it)) { 24 | Closure.class.getName() 25 | } else { 26 | String.valueOf(it) 27 | } 28 | }.join(', ') 29 | } 30 | 31 | @Override 32 | boolean equals(o) { 33 | if (this.is(o)) return true 34 | if (getClass() != o.class) return false 35 | 36 | MethodSignature that = (MethodSignature) o 37 | 38 | if (name != that.name) return false 39 | if (args == null && that.args == null) return true 40 | if (args.size() != that.args.size()) return false 41 | for (int i = 0; i < args.size(); i++) { 42 | Class thisClazz = this.args[i] 43 | Class thatClazz = that.args[i] 44 | if (!(isAssignableFrom(Closure.class, thatClazz) && isAssignableFrom(Closure.class, thisClazz))) { 45 | if (!isAssignableFrom(thisClazz, thatClazz)) { 46 | return false 47 | } 48 | } 49 | } 50 | return true 51 | } 52 | 53 | @Override 54 | int hashCode() { 55 | int result 56 | result = (name != null ? name.hashCode() : 0) 57 | result = 31 * result + (args != null ? argsToString().hashCode() : 0) 58 | return result 59 | } 60 | 61 | 62 | @Override 63 | String toString() { 64 | return "MethodSignature{ name='$name', args=${Arrays.toString(args)} }" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/MockPipelineScript.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | abstract class MockPipelineScript extends Script { 4 | 5 | /** 6 | * Override sleep method 7 | */ 8 | void sleep(long milliseconds) { 9 | // no-op 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/RegressionTest.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | trait RegressionTest { 4 | 5 | String callStackPath = "src/test/resources/callstacks/" 6 | 7 | /** 8 | * Checks the current callstack is the same as the reference callstack. 9 | * The reference callstack can be updated into a txt file in the callStackPath 10 | * 11 | * Pattern: /<_subname>.txt 12 | * @param subname optional subname, used in the reference callstack filename 13 | */ 14 | void testNonRegression(String subname = '') { 15 | String targetFileName = "${callStackPath}${this.class.simpleName}" 16 | if (subname) { 17 | targetFileName += "_${subname}" 18 | } 19 | RegressionTestHelper.testNonRegression(helper, targetFileName) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/VerificationException.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | /** 4 | * Custom exception class used in the verify method in BasePipelineTest 5 | */ 6 | class VerificationException extends Exception { 7 | 8 | VerificationException(String errorMessage) { 9 | super(errorMessage) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/cps/BasePipelineTestCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.cps 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import com.lesfurets.jenkins.unit.PipelineTestHelper 5 | 6 | class BasePipelineTestCPS extends BasePipelineTest { 7 | 8 | BasePipelineTestCPS(PipelineTestHelper helper) { 9 | super(helper) 10 | } 11 | 12 | BasePipelineTestCPS() { 13 | super(new PipelineTestHelperCPS()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/cps/BaseRegressionTestCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.cps 2 | 3 | import com.lesfurets.jenkins.unit.RegressionTest 4 | 5 | abstract class BaseRegressionTestCPS extends BasePipelineTestCPS implements RegressionTest { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/cps/MockClosure.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.cps 2 | 3 | import org.codehaus.groovy.runtime.InvokerHelper 4 | 5 | import com.cloudbees.groovy.cps.Block 6 | import com.cloudbees.groovy.cps.Env 7 | import com.cloudbees.groovy.cps.impl.CpsClosure 8 | 9 | class MockClosure extends CpsClosure { 10 | 11 | MockClosure(Object owner, Object thisObject, List parameters, Block body, Env capture) { 12 | super(owner, thisObject, parameters, body, capture) 13 | } 14 | 15 | /** 16 | * Override sleep method 17 | */ 18 | void sleep(long milliseconds) { 19 | InvokerHelper.invokeMethod(getOwner(), "sleep", milliseconds) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/cps/MockPipelineScriptCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.cps 2 | 3 | import com.lesfurets.jenkins.unit.MockPipelineScript 4 | 5 | abstract class MockPipelineScriptCPS extends MockPipelineScript implements Serializable { 6 | 7 | private void writeObject(ObjectOutputStream oos) throws IOException { 8 | // binding is defined in non-serializable Script class, 9 | // so we need to persist that here 10 | def variables = getBinding().getVariables().clone() 11 | oos.writeObject(variables) 12 | } 13 | 14 | private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 15 | Map m = (Map)ois.readObject() 16 | getBinding().getVariables().putAll(m) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/AgentDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import com.lesfurets.jenkins.unit.declarative.agent.DockerAgentDeclaration 4 | import com.lesfurets.jenkins.unit.declarative.agent.DockerfileAgentDeclaration 5 | import com.lesfurets.jenkins.unit.declarative.agent.KubernetesAgentDeclaration 6 | import groovy.transform.ToString 7 | 8 | import static groovy.lang.Closure.DELEGATE_FIRST 9 | 10 | @ToString(includePackage = false, includeNames = true, ignoreNulls = true) 11 | class AgentDeclaration extends GenericPipelineDeclaration { 12 | 13 | String label 14 | DockerAgentDeclaration docker 15 | KubernetesAgentDeclaration kubernetes 16 | DockerfileAgentDeclaration dockerfileAgent 17 | String customWorkspace 18 | def binding = null 19 | 20 | def label(String label) { 21 | this.label = label 22 | } 23 | 24 | def node(@DelegatesTo(AgentDeclaration) Closure closure) { 25 | closure.call() 26 | } 27 | 28 | def customWorkspace(String workspace) { 29 | this.customWorkspace = workspace 30 | } 31 | 32 | def docker(String image) { 33 | this.docker = new DockerAgentDeclaration().with { it.image = image; it } 34 | } 35 | 36 | def docker(@DelegatesTo(strategy = DELEGATE_FIRST, value = DockerAgentDeclaration) Closure closure) { 37 | this.docker = createComponent(DockerAgentDeclaration, closure) 38 | } 39 | 40 | def kubernetes(boolean _) { 41 | kubernetes([:]) 42 | } 43 | 44 | def kubernetes(Object kubernetesAgent) { 45 | this.@kubernetes = kubernetesAgent as KubernetesAgentDeclaration 46 | } 47 | 48 | def kubernetes(@DelegatesTo(strategy = DELEGATE_FIRST, value = KubernetesAgentDeclaration) Closure closure) { 49 | this.@kubernetes = createComponent(KubernetesAgentDeclaration, closure) 50 | } 51 | 52 | def dockerfile(boolean _) { 53 | dockerfile([:]) 54 | } 55 | 56 | def dockerfile(Object dockerfile) { 57 | this.@dockerfileAgent = dockerfile as DockerfileAgentDeclaration 58 | } 59 | 60 | def dockerfile(@DelegatesTo(strategy = DELEGATE_FIRST, value = DockerfileAgentDeclaration) Closure closure) { 61 | this.@dockerfileAgent = createComponent(DockerfileAgentDeclaration, closure) 62 | } 63 | 64 | 65 | def getCurrentBuild() { 66 | return binding?.currentBuild 67 | } 68 | 69 | def getEnv() { 70 | return binding?.env 71 | } 72 | 73 | def getParams() { 74 | return binding?.params 75 | } 76 | 77 | def execute(Object delegate) { 78 | def agentDesc = null 79 | 80 | if (label != null) { 81 | agentDesc = '[label:' + label.toString() + ']' 82 | } 83 | else if (docker) { 84 | agentDesc = '[docker:' + docker.toString() + ']' 85 | } 86 | else if (dockerfileAgent) { 87 | agentDesc = '[dockerfile:' + dockerfileAgent.toString() + ']' 88 | } 89 | else if (kubernetes) { 90 | agentDesc = '[kubernetes:' + kubernetes.toString() + ']' 91 | } 92 | else { 93 | throw new IllegalStateException("No agent description found") 94 | } 95 | executeWith(delegate, { echo "Executing on agent $agentDesc" }) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/AllOfDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import static groovy.lang.Closure.DELEGATE_FIRST 4 | 5 | class AllOfDeclaration extends WhenDeclaration { 6 | 7 | List> tags = [] 8 | List> branches = [] 9 | List changeRequests = [] 10 | List expressions = [] 11 | List anyOfs = [] 12 | 13 | def tag(String pattern) { 14 | tags.add(new Tuple2(pattern, ComparatorEnum.GLOB)) 15 | } 16 | 17 | def tag(Map args) { 18 | if (args.comparator) { 19 | ComparatorEnum comparator = ComparatorEnum.getComparator(args.comparator as String) 20 | this.tags.add(new Tuple2(args.pattern as String, comparator)) 21 | } 22 | else { 23 | tag(args.pattern) 24 | } 25 | } 26 | 27 | def branch(String pattern) { 28 | branches.add(new Tuple2(pattern, ComparatorEnum.GLOB)) 29 | } 30 | 31 | def branch(Map args) { 32 | if (args.comparator) { 33 | ComparatorEnum comparator = ComparatorEnum.getComparator(args.comparator as String) 34 | this.branches.add(new Tuple2(args.pattern as String, comparator)) 35 | } 36 | else { 37 | branch(args.pattern) 38 | } 39 | } 40 | 41 | def changeRequest(Object val) { 42 | this.changeRequests.add(new ChangeRequestDeclaration(val)) 43 | } 44 | 45 | def expression(Closure closure) { 46 | this.expressions.add(closure) 47 | } 48 | 49 | def anyOf(@DelegatesTo(strategy = DELEGATE_FIRST, value = AnyOfDeclaration) Closure closure) { 50 | this.anyOfs.add(createComponent(AnyOfDeclaration, closure)) 51 | } 52 | 53 | def expressions(Object delegate) { 54 | return this.expressions.collect {executeWith(delegate, it)}.every() 55 | } 56 | 57 | def anyOf(Object delegate) { 58 | return this.anyOfs.collect {it.execute(delegate)} 59 | } 60 | 61 | Boolean execute(Object delegate) { 62 | def results = [] 63 | 64 | if (tags) { 65 | tags.each { tag -> 66 | results.add(compareStringToPattern(delegate.env.TAG_NAME, tag)) 67 | } 68 | } 69 | 70 | if (branches) { 71 | branches.each { branch -> 72 | results.add(compareStringToPattern(delegate.env.BRANCH_NAME, branch)) 73 | } 74 | } 75 | 76 | if (changeRequests) { 77 | changeRequests.each { changeRequest -> 78 | results.add(changeRequest.execute(delegate)) 79 | } 80 | } 81 | 82 | if (expressions) { 83 | results.add(expressions(delegate)) 84 | } 85 | 86 | if (anyOfs) { 87 | results.addAll(anyOf(delegate)) 88 | } 89 | 90 | return results.every() 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/AnyOfDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.executeWith 4 | 5 | import static groovy.lang.Closure.DELEGATE_FIRST 6 | 7 | class AnyOfDeclaration extends WhenDeclaration { 8 | 9 | List> tags = [] 10 | List> branches = [] 11 | List changeRequests = [] 12 | List expressions = [] 13 | List allOfs = [] 14 | 15 | def tag(String pattern) { 16 | this.tags.add(new Tuple2(pattern, ComparatorEnum.GLOB)) 17 | } 18 | 19 | def tag(Map args) { 20 | if (args.comparator) { 21 | ComparatorEnum comparator = ComparatorEnum.getComparator(args.comparator as String) 22 | this.tags.add(new Tuple2(args.pattern as String, comparator)) 23 | } 24 | else { 25 | tag(args.pattern) 26 | } 27 | } 28 | 29 | def branch(String pattern) { 30 | this.branches.add(new Tuple2(pattern, ComparatorEnum.GLOB)) 31 | } 32 | 33 | def branch(Map args) { 34 | if (args.comparator) { 35 | ComparatorEnum comparator = ComparatorEnum.getComparator(args.comparator as String) 36 | this.branches.add(new Tuple2(args.pattern as String, comparator)) 37 | } 38 | else { 39 | branch(args.pattern) 40 | } 41 | } 42 | 43 | def changeRequest(Object val) { 44 | this.changeRequests.add(new ChangeRequestDeclaration(val)) 45 | } 46 | 47 | def expression(Closure closure) { 48 | this.expressions.add(closure) 49 | } 50 | 51 | def allOf(@DelegatesTo(strategy = DELEGATE_FIRST, value = AllOfDeclaration) Closure closure) { 52 | this.allOfs.add(createComponent(AllOfDeclaration, closure)) 53 | } 54 | 55 | def allOf(Object delegate) { 56 | return this.allOfs.collect {it.execute(delegate)} 57 | } 58 | 59 | def expressions(Object delegate) { 60 | return this.expressions.collect {executeWith(delegate, it)}.any() 61 | } 62 | 63 | Boolean execute(Object delegate) { 64 | def results = [] 65 | 66 | if (tags) { 67 | tags.each { tag -> 68 | results.add(compareStringToPattern(delegate.env.TAG_NAME, tag)) 69 | } 70 | } 71 | 72 | if (branches) { 73 | branches.each { branch -> 74 | results.add(compareStringToPattern(delegate.env.BRANCH_NAME, branch)) 75 | } 76 | } 77 | 78 | if (changeRequests) { 79 | changeRequests.each { changeRequest -> 80 | results.add(changeRequest.execute(delegate)) 81 | } 82 | } 83 | 84 | if (expressions) { 85 | results.add(expressions(delegate)) 86 | } 87 | 88 | if (allOfs) { 89 | results.addAll(allOf(delegate)) 90 | } 91 | 92 | return results.any() 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/ComparatorEnum.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | enum ComparatorEnum { 4 | 5 | EQUALS ('EQUALS'), 6 | GLOB ('GLOB'), 7 | REGEXP ('REGEXP') 8 | 9 | private static Map map 10 | 11 | static { 12 | map = [:] 13 | values().each { comparator -> 14 | map.put(comparator.name, comparator) 15 | } 16 | } 17 | 18 | static ComparatorEnum getComparator(String name) { 19 | return map.get(name) 20 | } 21 | 22 | private final String name 23 | 24 | private ComparatorEnum(String name) { 25 | this.name = name 26 | } 27 | 28 | @Override 29 | String toString() { 30 | return this.name 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/DeclarativePipeline.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import static groovy.lang.Closure.* 4 | 5 | class DeclarativePipeline extends GenericPipelineDeclaration { 6 | 7 | def properties = [:] 8 | List options = [] 9 | 10 | Closure triggers 11 | ParametersDeclaration params = null 12 | 13 | DeclarativePipeline() { 14 | properties.put('any', 'any') 15 | properties.put('none', 'none') 16 | properties.put('scm', 'scm') 17 | } 18 | 19 | def propertyMissing(String name) { 20 | if (properties.containsKey(name)) { 21 | return properties.get(name) 22 | } else { 23 | throw new MissingPropertyException(name) 24 | } 25 | } 26 | 27 | def propertyMissing(String name, arg) { 28 | 29 | } 30 | 31 | def options(@DelegatesTo(DeclarativePipeline) Closure closure) { 32 | options.add(closure) 33 | } 34 | 35 | def triggers(@DelegatesTo(DeclarativePipeline) Closure closure) { 36 | this.triggers = closure 37 | } 38 | 39 | def parameters(Object o) { 40 | this.params = new ParametersDeclaration().with { it.label = o; it } 41 | } 42 | 43 | def parameters(@DelegatesTo(strategy=DELEGATE_FIRST, value=ParametersDeclaration) Closure closure) { 44 | this.params = createComponent(ParametersDeclaration, closure) 45 | } 46 | 47 | def execute(Object delegate) { 48 | super.execute(delegate) 49 | this.options.forEach { 50 | executeOn(delegate, it) 51 | } 52 | this.agent?.execute(delegate) 53 | executeOn(delegate, this.triggers) 54 | this.stages.entrySet().forEach { e -> 55 | e.value.execute(delegate) 56 | } 57 | this.post?.execute(delegate) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/DeclarativePipelineTest.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | 5 | import static com.lesfurets.jenkins.unit.MethodSignature.method 6 | 7 | @groovy.transform.InheritConstructors 8 | abstract class DeclarativePipelineTest extends BasePipelineTest { 9 | 10 | def pipelineInterceptor = { Closure closure -> 11 | GenericPipelineDeclaration.binding = binding 12 | GenericPipelineDeclaration.createComponent(DeclarativePipeline, closure).execute(delegate) 13 | } 14 | 15 | @Override 16 | void setUp() throws Exception { 17 | super.setUp() 18 | helper.registerAllowedMethod('booleanParam', [Map], paramInterceptor) 19 | helper.registerAllowedMethod('checkout', [Closure]) 20 | helper.registerAllowedMethod('credentials', [String], { String credName -> 21 | return binding.getVariable('credentials')[credName] 22 | }) 23 | helper.registerAllowedMethod('cron', [String]) 24 | helper.registerAllowedMethod('input', [Closure]) 25 | helper.registerAllowedMethod('message', [String]) 26 | helper.registerAllowedMethod(method("pipeline", Closure), pipelineInterceptor) 27 | helper.registerAllowedMethod('pollSCM', [String]) 28 | helper.registerAllowedMethod('script', [Closure]) 29 | helper.registerAllowedMethod('skipDefaultCheckout') 30 | helper.registerAllowedMethod('string', [Map], stringInterceptor) 31 | helper.registerAllowedMethod('timeout', [Integer, Closure]) 32 | helper.registerAllowedMethod('timestamps') 33 | binding.setVariable('credentials', [:]) 34 | binding.setVariable('params', [:].asImmutable()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/NotDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | class NotDeclaration extends WhenDeclaration { 4 | 5 | Boolean execute(Object delegate) { 6 | return !super.execute(delegate) 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/ObjectUtils.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | class ObjectUtils { 4 | 5 | static String printNonNullProperties(Object obj) { 6 | def props = obj.properties.clone() 7 | props.remove('class') 8 | props.remove('binding') 9 | obj.properties.entrySet().forEach { e -> 10 | if (e.value == null) { 11 | props.remove(e.key) 12 | } 13 | } 14 | return props.toString() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/ParallelDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import static groovy.lang.Closure.DELEGATE_FIRST 4 | //import static com.lesfurets.jenkins.unit.declarative.DeclarativePipeline.executeOn 5 | 6 | class ParallelDeclaration extends GenericPipelineDeclaration { 7 | 8 | boolean failFast 9 | 10 | ParallelDeclaration(boolean failFast) { 11 | this.failFast = failFast 12 | } 13 | 14 | ParallelDeclaration() { 15 | this.failFast = false 16 | } 17 | 18 | def stage(String name, 19 | @DelegatesTo(strategy = DELEGATE_FIRST, value = StageDeclaration) Closure closure) { 20 | this.stages.put(name, createComponent(StageDeclaration, closure).with{it.name = name;it} ) 21 | } 22 | 23 | def execute(Object delegate) { 24 | super.execute(delegate) 25 | this.stages.entrySet().forEach { e -> 26 | e.value.execute(delegate) 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/ParametersDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | 4 | class ParametersDeclaration extends GenericPipelineDeclaration { 5 | 6 | void setParams(String name, Object val) { 7 | Map immutableParams = binding.getVariable('params') as Map 8 | if (immutableParams[name] == null) { 9 | Map mutableParams = [:] 10 | immutableParams.each { k, v -> mutableParams[k] = v } 11 | mutableParams[name] = val 12 | binding.setVariable('params', mutableParams.asImmutable()) 13 | } 14 | } 15 | 16 | // dereference 'parameters closure 17 | def booleanParam(Map val) { 18 | this.setParams(val.name, val.defaultValue) 19 | } 20 | 21 | def choice(Map val) { 22 | this.setParams(val.name, val.choices[0]) 23 | } 24 | 25 | def password(Map val) { 26 | this.setParams(val.name, val.defaultValue) 27 | } 28 | 29 | def string(Map val) { 30 | this.setParams(val.name, val.defaultValue) 31 | } 32 | 33 | def text(Map val) { 34 | this.setParams(val.name, val.defaultValue) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/PostDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import static com.lesfurets.jenkins.unit.declarative.DeclarativePipeline.executeOn 4 | 5 | class PostDeclaration { 6 | 7 | Closure always 8 | Closure changed 9 | Closure success 10 | Closure unstable 11 | Closure failure 12 | Closure aborted 13 | Closure unsuccessful 14 | Closure cleanup 15 | Closure fixed 16 | Closure regression 17 | 18 | def always(Closure closure) { 19 | this.always = closure 20 | } 21 | 22 | def changed(Closure closure) { 23 | this.changed = closure 24 | } 25 | 26 | def success(Closure closure) { 27 | this.success = closure 28 | } 29 | 30 | def unstable(Closure closure) { 31 | this.unstable = closure 32 | } 33 | 34 | def unsuccessful(Closure closure) { 35 | this.unsuccessful = closure 36 | } 37 | 38 | def failure(Closure closure) { 39 | this.failure = closure 40 | } 41 | 42 | def aborted(Closure closure) { 43 | this.aborted = closure 44 | } 45 | 46 | def cleanup(Closure closure) { 47 | this.cleanup = closure 48 | } 49 | 50 | def fixed(Closure closure) { 51 | this.fixed = closure 52 | } 53 | 54 | def regression(Closure closure){ 55 | this.regression = closure 56 | } 57 | 58 | def execute(Object delegate) { 59 | def currentBuild = delegate.currentBuild.result 60 | def previousBuild = delegate.currentBuild?.previousBuild?.result 61 | if (this.always) { 62 | executeOn(delegate, this.always) 63 | } 64 | 65 | switch (currentBuild) { 66 | case 'SUCCESS': 67 | executeOn(delegate, this.success) 68 | break 69 | case 'FAILURE': 70 | executeOn(delegate, this.failure) 71 | break 72 | case 'ABORTED': 73 | executeOn(delegate, this.aborted) 74 | break 75 | case 'UNSTABLE': 76 | executeOn(delegate, this.unstable) 77 | break 78 | } 79 | 80 | if(currentBuild != previousBuild && this.changed) 81 | { 82 | executeOn(delegate, this.changed) 83 | } 84 | if(currentBuild != 'SUCCESS' && this.unsuccessful) 85 | { 86 | executeOn(delegate, this.unsuccessful) 87 | } 88 | if(this.fixed){ 89 | if(currentBuild == 'SUCCESS' && (previousBuild == 'FAILURE' || previousBuild == 'UNSTABLE')) 90 | { 91 | executeOn(delegate, this.fixed) 92 | } 93 | } 94 | if(this.regression) 95 | { 96 | if((currentBuild == 'FAILURE' || currentBuild == 'UNSTABLE') && previousBuild == 'SUCCESS'){ 97 | executeOn(delegate, this.regression) 98 | } 99 | } 100 | 101 | // Cleanup is always performed last 102 | if(this.cleanup){ 103 | executeOn(delegate, this.cleanup) 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/StageDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | 4 | import static groovy.lang.Closure.* 5 | 6 | class StageDeclaration extends GenericPipelineDeclaration { 7 | 8 | String name 9 | Closure steps 10 | WhenDeclaration when 11 | ParallelDeclaration parallel 12 | boolean failFast = false 13 | List options = [] 14 | 15 | StageDeclaration(String name) { 16 | this.name = name 17 | } 18 | 19 | def steps(Closure closure) { 20 | this.steps = closure 21 | } 22 | 23 | def failFast(boolean failFast) { 24 | this.failFast = failFast 25 | } 26 | 27 | def getBinding_var() { 28 | return binding?.var 29 | } 30 | 31 | def parallel(@DelegatesTo(strategy = DELEGATE_FIRST, value = ParallelDeclaration) Closure closure) { 32 | this.parallel = createComponent(ParallelDeclaration, closure).with { it.failFast = failFast; it } 33 | } 34 | 35 | def when(@DelegatesTo(strategy = DELEGATE_FIRST, value = WhenDeclaration) Closure closure) { 36 | this.when = createComponent(WhenDeclaration, closure) 37 | } 38 | 39 | def options(@DelegatesTo(StageDeclaration) Closure closure) { 40 | options.add(closure) 41 | } 42 | 43 | def execute(Object delegate) { 44 | String name = this.name 45 | def actions = 0 46 | if(parallel) { 47 | actions++ 48 | } 49 | if(stages.size()>0) { 50 | actions++ 51 | } 52 | if(steps) { 53 | actions++ 54 | } 55 | if (actions > 1 ) { 56 | throw new IllegalArgumentException ("""Only one of "matrix", "parallel", "stages", or "steps" allowed for stage "${name}" """) 57 | } 58 | 59 | this.options.each { 60 | executeOn(delegate, it) 61 | } 62 | 63 | if(delegate.binding.variables.currentBuild.result == "FAILURE"){ 64 | executeWith(delegate, { echo "Stage \"$name\" skipped due to earlier failure(s)" }) 65 | return 66 | } 67 | 68 | if (!when || when.execute(delegate)) { 69 | super.execute(delegate) 70 | 71 | // TODO handle credentials 72 | 73 | if (parallel) { 74 | parallel.execute(delegate) 75 | } 76 | 77 | Closure stageBody = { agent?.execute(delegate) } 78 | Closure cl = { stage("$name", stageBody) } 79 | if (steps) { 80 | stageBody = stageBody >> steps.rehydrate(delegate, this, delegate) 81 | } 82 | executeWith(delegate, cl) 83 | 84 | this.stages.entrySet().forEach { e -> 85 | e.value.execute(delegate) 86 | } 87 | 88 | if (post) { 89 | this.post.execute(delegate) 90 | } 91 | } else { 92 | executeWith(delegate, { echo "Skipping stage $name" }) 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/agent/DockerAgentDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative.agent 2 | 3 | import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration 4 | import groovy.transform.Memoized 5 | import groovy.transform.ToString 6 | 7 | import static com.lesfurets.jenkins.unit.declarative.ObjectUtils.printNonNullProperties 8 | 9 | @ToString(includePackage = false, includeNames = true, ignoreNulls = true) 10 | class DockerAgentDeclaration extends GenericPipelineDeclaration { 11 | 12 | String label 13 | String args = "" 14 | String registryUrl 15 | String registryCredentialsId 16 | String customWorkspace 17 | boolean reuseNode 18 | boolean containerPerStageRoot 19 | boolean alwaysPull 20 | String image 21 | 22 | def label(final String label) { 23 | this.label = label 24 | } 25 | 26 | def args(final String args) { 27 | this.args = args 28 | } 29 | 30 | def alwaysPull(final boolean alwaysPull) { 31 | this.alwaysPull = alwaysPull 32 | } 33 | 34 | def registryUrl(final String registryUrl) { 35 | this.registryUrl = registryUrl 36 | } 37 | 38 | def registryCredentialsId(final String registryCredentialsId) { 39 | this.registryCredentialsId = registryCredentialsId 40 | } 41 | 42 | def customWorkspace(final String customWorkspace) { 43 | this.customWorkspace = customWorkspace 44 | } 45 | 46 | def reuseNode(final boolean reuseNode) { 47 | this.reuseNode = reuseNode 48 | } 49 | 50 | def containerPerStageRoot(final boolean containerPerStageRoot) { 51 | this.containerPerStageRoot = containerPerStageRoot 52 | } 53 | 54 | def image(String image) { 55 | this.image = image 56 | } 57 | 58 | @Memoized 59 | String toString() { 60 | return printNonNullProperties(this) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/agent/DockerfileAgentDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative.agent 2 | 3 | 4 | import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration 5 | import groovy.transform.ToString 6 | 7 | @ToString(includePackage = false, includeNames = true, ignoreNulls = true) 8 | class DockerfileAgentDeclaration extends GenericPipelineDeclaration { 9 | String additionalBuildArgs 10 | String args 11 | String customWorkspace 12 | String dockerfileDir 13 | String filename 14 | String label 15 | String registryCredentialsId 16 | String registryUrl 17 | Boolean reuseNode 18 | 19 | def additionalBuildArgs(String additionalBuildArgs) { 20 | this.additionalBuildArgs = additionalBuildArgs 21 | } 22 | 23 | def args(String args) { 24 | this.args = args 25 | } 26 | 27 | def customWorkspace(final String customWorkspace) { 28 | this.customWorkspace = customWorkspace 29 | } 30 | 31 | def dir(String dir) { 32 | this.dockerfileDir = dir 33 | } 34 | 35 | def filename(String filename) { 36 | this.filename = filename 37 | } 38 | 39 | def label(final String label) { 40 | this.label = label 41 | } 42 | 43 | def registryCredentialsId(final String registryCredentialsId) { 44 | this.registryCredentialsId = registryCredentialsId 45 | } 46 | 47 | def registryUrl(final String registryUrl) { 48 | this.registryUrl = registryUrl 49 | } 50 | 51 | def reuseNode(boolean reuse) { 52 | this.reuseNode = reuse 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/kubernetes/ContainerLivenessProbeDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative.kubernetes 2 | 3 | import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration 4 | 5 | class ContainerLivenessProbeDeclaration extends GenericPipelineDeclaration { 6 | 7 | String execArgs 8 | int timeoutSeconds 9 | int initialDelaySeconds 10 | int failureThreshold 11 | int periodSeconds 12 | int successThreshold 13 | 14 | def execArgs(final String execArgs) { 15 | this.execArgs = execArgs 16 | } 17 | 18 | def timeoutSeconds(final int timeoutSeconds) { 19 | this.timeoutSeconds = timeoutSeconds 20 | } 21 | 22 | def initialDelaySeconds(final int initialDelaySeconds) { 23 | this.initialDelaySeconds = initialDelaySeconds 24 | } 25 | 26 | def failureThreshold(final int failureThreshold) { 27 | this.failureThreshold = failureThreshold 28 | } 29 | 30 | def periodSeconds(final int periodSeconds) { 31 | this.periodSeconds = periodSeconds 32 | } 33 | 34 | def successThreshold(final int successThreshold) { 35 | this.successThreshold = successThreshold 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/kubernetes/PodTemplateDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative.kubernetes 2 | 3 | import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration 4 | 5 | 6 | class PodTemplateDeclaration extends GenericPipelineDeclaration { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/kubernetes/PortMappingDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative.kubernetes 2 | 3 | import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration 4 | import groovy.transform.Memoized 5 | import groovy.transform.ToString 6 | 7 | import static com.lesfurets.jenkins.unit.declarative.ObjectUtils.printNonNullProperties 8 | 9 | @ToString(includePackage = false, includeNames = true, ignoreNulls = true) 10 | class PortMappingDeclaration extends GenericPipelineDeclaration { 11 | String name 12 | int containerPort 13 | int hostPort 14 | 15 | def name(final String name) { 16 | this.name = name 17 | } 18 | 19 | def containerPort(final int containerPort) { 20 | this.containerPort = containerPort 21 | } 22 | 23 | def hostPort(final int hostPort) { 24 | this.hostPort = hostPort 25 | } 26 | 27 | @Memoized 28 | String toString() { 29 | return printNonNullProperties(this) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/declarative/kubernetes/TemplateEnvVarDeclaration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative.kubernetes 2 | 3 | import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration 4 | 5 | class TemplateEnvVarDeclaration extends GenericPipelineDeclaration { 6 | 7 | KeyValueVar containerEnvVar; 8 | KeyValueVar envVar; 9 | KeyValueVar podEnvVar; 10 | KeyValueVar secretEnvVar; 11 | 12 | def containerEnvVar(final KeyValueVar containerEnvVar) { 13 | this.containerEnvVar = containerEnvVar 14 | } 15 | 16 | def envVar(final KeyValueVar envVar) { 17 | this.envVar = envVar 18 | } 19 | 20 | def podEnvVar(final KeyValueVar podEnvVar) { 21 | this.podEnvVar = podEnvVar 22 | } 23 | 24 | def secretEnvVar(final KeyValueVar secretEnvVar) { 25 | this.secretEnvVar = secretEnvVar 26 | } 27 | 28 | class KeyValueVar { 29 | String key 30 | String value 31 | 32 | def key(final String key) { 33 | this.key = key 34 | } 35 | 36 | def value(final String value) { 37 | this.value = value 38 | } 39 | } 40 | 41 | class SecretVar { 42 | String key 43 | String secretName 44 | String secretKey 45 | boolean optional 46 | 47 | def key(final String key) { 48 | this.key = key 49 | } 50 | 51 | def secretName(final String secretName) { 52 | this.secretName = secretName 53 | } 54 | 55 | def secretKey(final String secretKey) { 56 | this.secretKey = secretKey 57 | } 58 | 59 | def optional(final boolean optional) { 60 | this.optional = optional 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/GitSource.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | import java.util.concurrent.TimeUnit 4 | 5 | import groovy.transform.CompileStatic 6 | import groovy.transform.Immutable 7 | 8 | @Immutable 9 | @CompileStatic 10 | class GitSource implements SourceRetriever { 11 | 12 | String sourceURL 13 | 14 | @Override 15 | List retrieve(String repository, String branch, String targetPath) throws IllegalStateException { 16 | File target = new File(targetPath) 17 | def fetch = target.toPath().resolve("$repository@$branch").toFile() 18 | if (fetch.exists()) { 19 | return [fetch.toURI().toURL()] 20 | } else { 21 | fetch.parentFile.mkdirs() 22 | } 23 | def command = "git clone -b $branch --single-branch $sourceURL $repository@$branch" 24 | println command 25 | def processBuilder = new ProcessBuilder(command.split(' ')) 26 | .inheritIO() 27 | .directory(target) 28 | def proc = processBuilder.start() 29 | proc.waitFor(CLONE_TIMEOUT_MIN, TimeUnit.MINUTES) 30 | proc.exitValue() 31 | return [fetch.toURI().toURL()] 32 | } 33 | 34 | static GitSource gitSource(String source) { 35 | new GitSource(source) 36 | } 37 | 38 | @Override 39 | String toString() { 40 | return "GitSource{" + 41 | "sourceURL='" + sourceURL + '\'' + 42 | '}' 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/Library.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | /** 4 | * Annotation definition to avoid missing import 5 | */ 6 | @interface Library { 7 | 8 | /** 9 | * Library names, each optionally followed by {@code @} and a version. 10 | */ 11 | String[] value() 12 | 13 | } -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LibraryConfiguration.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.builder.Builder 5 | import groovy.transform.builder.ExternalStrategy 6 | 7 | /** 8 | * Mock for org.jenkinsci.plugins.workflow.libs.LibraryConfiguration 9 | */ 10 | @CompileStatic 11 | class LibraryConfiguration { 12 | 13 | String name 14 | String defaultVersion = 'master' 15 | SourceRetriever retriever 16 | boolean implicit = false 17 | boolean allowOverride = true 18 | String targetPath 19 | 20 | LibraryConfiguration validate() { 21 | if (name && defaultVersion && retriever && targetPath) 22 | return this 23 | throw new IllegalStateException("LibraryConfiguration is not properly initialized ${this.toString()}") 24 | } 25 | 26 | static LibraryBuilder library(String libName = null) { 27 | return new LibraryBuilder() { 28 | LibraryConfiguration build() { return super.build().validate() } 29 | }.with { it.name(libName) } 30 | } 31 | 32 | @Builder(builderStrategy = ExternalStrategy, forClass = LibraryConfiguration) 33 | static class LibraryBuilder { 34 | 35 | } 36 | 37 | @Override 38 | String toString() { 39 | return "LibraryConfiguration{" + 40 | "name='" + name + '\'' + 41 | ", defaultVersion='" + defaultVersion + '\'' + 42 | ", retriever=" + retriever + 43 | ", implicit=" + implicit + 44 | ", allowOverride=" + allowOverride + 45 | '}' 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LibraryRecord.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | import groovy.transform.CompileStatic 4 | 5 | @CompileStatic 6 | class LibraryRecord { 7 | 8 | LibraryConfiguration configuration 9 | String version 10 | List rootPaths 11 | 12 | Map definedGlobalVars 13 | 14 | LibraryRecord(LibraryConfiguration configuration, String version, List rootPaths) { 15 | this.configuration = configuration 16 | this.version = version 17 | this.rootPaths = rootPaths 18 | } 19 | 20 | String getIdentifier() { 21 | return "$configuration.name@$version" 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LocalSource.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.Immutable 5 | 6 | @Immutable 7 | @CompileStatic 8 | class LocalSource implements SourceRetriever { 9 | 10 | String sourceURL 11 | 12 | @Override 13 | List retrieve(String repository, String branch, String targetPath) { 14 | def sourceDir = new File(sourceURL).toPath().resolve("$repository@$branch").toFile() 15 | if (sourceDir.exists()) { 16 | return [sourceDir.toURI().toURL()] 17 | } 18 | throw new IllegalStateException("Directory $sourceDir.path does not exists") 19 | } 20 | 21 | static LocalSource localSource(String source) { 22 | new LocalSource(source) 23 | } 24 | 25 | @Override 26 | String toString() { 27 | return "LocalSource{" + 28 | "sourceURL='" + sourceURL + '\'' + 29 | '}' 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/ProjectSource.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | import com.lesfurets.jenkins.unit.global.lib.SourceRetriever 4 | 5 | import groovy.transform.CompileStatic 6 | import groovy.transform.Immutable 7 | 8 | /** 9 | * Retrieves the shared lib sources of the current project which are expected to be 10 | * at the default location ("./vars"), "./src", "./resources"). 11 | * When working with this retriever the LibraryConfiguration which is provided 12 | * with this SourceRetrievers should be configured with allowOverride=false 13 | * since the ProjectSource retriever does not support loading of alternate versions. As 14 | * already outlined above this source retriever always loads the version as it is 15 | * contained at the default location. 16 | */ 17 | 18 | @Immutable 19 | @CompileStatic 20 | class ProjectSource implements SourceRetriever { 21 | 22 | String sourceURL 23 | 24 | /* 25 | * None of the parameters provided in the signature are used in the use-case of that retriever. 26 | */ 27 | @Override 28 | List retrieve(String repository, String branch, String targetPath) { 29 | def sourceDir = new File(sourceURL) 30 | if (sourceDir.exists()) { 31 | return [sourceDir.getAbsoluteFile().toURI().toURL()] 32 | } 33 | throw new IllegalStateException("Directory $sourceDir.path does not exists") 34 | } 35 | 36 | static ProjectSource projectSource(String sourceDir = '.') { 37 | new ProjectSource(sourceDir) 38 | } 39 | 40 | @Override 41 | String toString() { 42 | return "${getClass().getSimpleName()}{" + 43 | "sourceURL='" + sourceURL + '\'' + 44 | '}' 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/groovy/com/lesfurets/jenkins/unit/global/lib/SourceRetriever.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.global.lib 2 | 3 | import groovy.transform.CompileStatic 4 | 5 | @CompileStatic 6 | interface SourceRetriever { 7 | 8 | public static final int CLONE_TIMEOUT_MIN = 10 9 | 10 | List retrieve(String repository, String branch, String targetPath) throws IllegalStateException 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/groovy/com/TestCatchError.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | class TestCatchError extends BasePipelineTest { 8 | 9 | @Override 10 | @Before 11 | void setUp() throws Exception { 12 | super.setUp() 13 | } 14 | 15 | @Test() 16 | void should_fail_with_fail_before_and_SuccesCatch() throws Exception { 17 | def script = runInlineScript(""" 18 | node() { 19 | stage('test') { 20 | error 'error' 21 | catchError(buildResult: 'SUCCESS') { 22 | throw new Exception() 23 | } 24 | } 25 | } 26 | """) 27 | assertJobStatusFailure() 28 | } 29 | 30 | @Test() 31 | void should_unstable_with_unstable_before_and_SuccesCatch() throws Exception { 32 | def script = runInlineScript(""" 33 | node() { 34 | stage('test') { 35 | unstable 'unstable' 36 | catchError(buildResult: 'SUCCESS') { 37 | throw new Exception() 38 | } 39 | } 40 | } 41 | """) 42 | assertJobStatusUnstable() 43 | } 44 | 45 | @Test() 46 | void should_succes_with_SuccesCatch() throws Exception { 47 | def script = runInlineScript(""" 48 | node() { 49 | stage('test') { 50 | catchError(buildResult: 'SUCCESS') { 51 | throw new Exception() 52 | } 53 | } 54 | } 55 | """) 56 | assertJobStatusSuccess() 57 | } 58 | 59 | @Test() 60 | void should_unstable_with_UnstableCatch() throws Exception { 61 | def script = runInlineScript(""" 62 | node() { 63 | stage('test') { 64 | catchError(buildResult: 'UNSTABLE') { 65 | throw new Exception() 66 | } 67 | } 68 | } 69 | """) 70 | assertJobStatusUnstable() 71 | } 72 | 73 | @Test() 74 | void should_fail_with_no_parameter() throws Exception { 75 | def script = runInlineScript(""" 76 | node() { 77 | stage('test') { 78 | catchError() { 79 | throw new Exception() 80 | } 81 | } 82 | } 83 | """) 84 | assertJobStatusFailure() 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestAddCredential.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import org.junit.Test 5 | 6 | class TestAddCredential extends BasePipelineTest { 7 | 8 | @Test 9 | void readUndefinedParamNoException() throws Exception { 10 | super.setUp() 11 | addCredential('FOO', 'BAR') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestAddEnvVar.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import org.junit.Test 5 | 6 | class TestAddEnvVar extends BasePipelineTest { 7 | 8 | @Test 9 | void readUndefinedParamNoException() throws Exception { 10 | super.setUp() 11 | addEnvVar('FOO', 'BAR') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestAddParam.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import org.junit.Test 5 | 6 | class TestAddParam extends BasePipelineTest { 7 | 8 | @Test 9 | void readUndefinedParamNoException() throws Exception { 10 | super.setUp() 11 | addParam('FOO', 'BAR') 12 | } 13 | 14 | @Test(expected = UnsupportedOperationException) 15 | void addParamImmutable() throws Exception { 16 | super.setUp() 17 | addParam('FOO', 'BAR') 18 | 19 | // We should not be able to modify existing parameters. This would not work on Jenkins. 20 | binding.getVariable('params')['FOO'] = 'NOT-BAR' 21 | } 22 | 23 | @Test(expected = UnsupportedOperationException) 24 | void addNewParamImmutable() throws Exception { 25 | super.setUp() 26 | 27 | // It also is not permitted to add new parameters directly. Instead, addParam must be used. 28 | binding.getVariable('params')['BAZ'] = 'QUX' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestCustomMethodJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | import static org.junit.Assert.assertTrue 8 | 9 | class TestCustomMethodJob extends BasePipelineTest { 10 | 11 | @Override 12 | @Before 13 | void setUp() throws Exception { 14 | scriptRoots += 'src/test/jenkins' 15 | super.setUp() 16 | } 17 | 18 | @Test 19 | void should_run_script_with_custom_method() { 20 | // when: 21 | runScript("job/customMethod.jenkins") 22 | 23 | // then: 24 | assertJobStatusSuccess() 25 | assertTrue(helper.callStack.find { call -> 26 | call.methodName == 'echo' 27 | }.argsToString() == 'executing custom method closure') 28 | } 29 | 30 | @Test 31 | void should_run_script_with_custom_method_mock() { 32 | // given: 33 | Closure customMethodMock = { echo 'executing mock closure' } 34 | helper.registerAllowedMethod('customMethod', [], customMethodMock) 35 | 36 | // when: 37 | runScript("job/customMethod.jenkins") 38 | 39 | // then: 40 | assertJobStatusSuccess() 41 | assertTrue(helper.callStack.find { call -> 42 | call.methodName == 'echo' 43 | }.argsToString() == 'executing mock closure') 44 | } 45 | 46 | @Test 47 | void should_run_script_with_custom_method_with_arguments() { 48 | // when: 49 | runScript("job/customMethodWithArguments.jenkins") 50 | 51 | // then: 52 | assertJobStatusSuccess() 53 | assertTrue(helper.callStack.find { call -> 54 | call.methodName == 'echo' 55 | }.argsToString() == 'executing custom method with arguments closure (arguments: \'stringArg\', \'42\', \'[collectionArg, 42]\')') 56 | } 57 | 58 | @Test 59 | void should_run_script_with_custom_method_with_arguments_mock() { 60 | // given: 61 | Closure customMethodWithArgumentsMock = { String stringArg, int intArg, Collection collectionArg -> 62 | echo "executing mock closure with arguments (arguments: '${stringArg}', '${intArg}', '${collectionArg}')" 63 | } 64 | helper.registerAllowedMethod('customMethodWithArguments', [String, int, Collection], customMethodWithArgumentsMock) 65 | 66 | // when: 67 | runScript("job/customMethodWithArguments.jenkins") 68 | 69 | // then: 70 | assertJobStatusSuccess() 71 | assertTrue(helper.callStack.find { call -> 72 | call.methodName == 'echo' 73 | }.argsToString() == 'executing mock closure with arguments (arguments: \'stringArg\', \'42\', \'[collectionArg, 42]\')') 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestCustomMethodJobCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.cps.BasePipelineTestCPS 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | import static org.junit.Assert.assertTrue 8 | 9 | class TestCustomMethodJobCPS extends BasePipelineTestCPS { 10 | 11 | @Override 12 | @Before 13 | void setUp() throws Exception { 14 | scriptRoots += 'src/test/jenkins' 15 | super.setUp() 16 | } 17 | 18 | @Test 19 | void should_run_script_with_custom_method() { 20 | // when: 21 | runScript("job/customMethod.jenkins") 22 | 23 | // then: 24 | assertJobStatusSuccess() 25 | assertTrue(helper.callStack.find { call -> 26 | call.methodName == 'echo' 27 | }.argsToString() == 'executing custom method closure') 28 | } 29 | 30 | @Test 31 | void should_run_script_with_custom_method_mock() { 32 | // given: 33 | Closure customMethodMock = { echo 'executing mock closure' } 34 | helper.registerAllowedMethod('customMethod', [], customMethodMock) 35 | 36 | // when: 37 | runScript("job/customMethod.jenkins") 38 | 39 | // then: 40 | assertJobStatusSuccess() 41 | assertTrue(helper.callStack.find { call -> 42 | call.methodName == 'echo' 43 | }.argsToString() == 'executing mock closure') 44 | } 45 | 46 | @Test 47 | void should_run_script_with_custom_method_with_arguments() { 48 | // when: 49 | runScript("job/customMethodWithArguments.jenkins") 50 | 51 | // then: 52 | assertJobStatusSuccess() 53 | assertTrue(helper.callStack.find { call -> 54 | call.methodName == 'echo' 55 | }.argsToString() == 'executing custom method with arguments closure (arguments: \'stringArg\', \'42\', \'[collectionArg, 42]\')') 56 | } 57 | 58 | @Test 59 | void should_run_script_with_custom_method_with_arguments_mock() { 60 | // given: 61 | Closure customMethodWithArgumentsMock = { String stringArg, int intArg, Collection collectionArg -> 62 | echo "executing mock closure with arguments (arguments: '${stringArg}', '${intArg}', '${collectionArg}')" 63 | } 64 | helper.registerAllowedMethod('customMethodWithArguments', [String, int, Collection], customMethodWithArgumentsMock) 65 | 66 | // when: 67 | runScript("job/customMethodWithArguments.jenkins") 68 | 69 | // then: 70 | assertJobStatusSuccess() 71 | assertTrue(helper.callStack.find { call -> 72 | call.methodName == 'echo' 73 | }.argsToString() == 'executing mock closure with arguments (arguments: \'stringArg\', \'42\', \'[collectionArg, 42]\')') 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestDeclarativeImmutableParams.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.declarative.DeclarativePipelineTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | import static org.junit.Assert.assertEquals 8 | 9 | class TestDeclarativeImmutableParams extends DeclarativePipelineTest { 10 | 11 | @Override 12 | @Before 13 | void setUp() throws Exception { 14 | scriptRoots += 'src/test/jenkins' 15 | 16 | super.setUp() 17 | } 18 | 19 | @Test(expected = UnsupportedOperationException) 20 | void "test immutable params in declarative pipeline"() { 21 | runScript("job/library/test_params_immutable_declarative.jenkins") 22 | assertEquals('original', binding.params['new'].toString()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestExampleJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import com.lesfurets.jenkins.unit.BasePipelineTest 7 | 8 | import static com.lesfurets.jenkins.unit.MethodCall.callArgsToString 9 | import static org.junit.Assert.assertTrue 10 | 11 | class TestExampleJob extends BasePipelineTest { 12 | 13 | @Override 14 | @Before 15 | void setUp() throws Exception { 16 | scriptRoots += 'src/test/jenkins' 17 | super.setUp() 18 | def scmBranch = "feature_test" 19 | helper.registerAllowedMethod("sh", [Map.class], {c -> 'bcc19744'}) 20 | binding.setVariable('scm', [ 21 | $class : 'GitSCM', 22 | branches : [[name: scmBranch]] 23 | ]) 24 | } 25 | 26 | @Test 27 | void should_execute_without_errors() throws Exception { 28 | def script = runScript("job/exampleJob.jenkins") 29 | script.execute() 30 | printCallStack() 31 | assertJobStatusSuccess() 32 | } 33 | 34 | @Test 35 | void should_print_property_value() { 36 | def script = runScript('job/exampleJob.jenkins') 37 | script.execute() 38 | 39 | def value = 'value' 40 | assertTrue(helper.callStack.findAll { call -> 41 | call.methodName == 'println' 42 | }.any { call -> 43 | callArgsToString(call).contains(value) 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestExampleJobCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import static com.lesfurets.jenkins.unit.MethodCall.callArgsToString 4 | import static org.junit.Assert.assertTrue 5 | 6 | import org.junit.Before 7 | import org.junit.Test 8 | 9 | import com.lesfurets.jenkins.unit.cps.BasePipelineTestCPS 10 | 11 | class TestExampleJobCPS extends BasePipelineTestCPS { 12 | 13 | @Override 14 | @Before 15 | void setUp() throws Exception { 16 | scriptRoots += 'src/test/jenkins' 17 | super.setUp() 18 | def scmBranch = "feature_test" 19 | helper.registerAllowedMethod("sh", [Map.class], {c -> "bcc19744fc4876848f3a21aefc92960ea4c716cf"}) 20 | binding.setVariable('scm', [ 21 | $class : 'GitSCM', 22 | branches : [[name: scmBranch]] 23 | ]) 24 | } 25 | 26 | @Test 27 | void should_execute_without_errors() throws Exception { 28 | def script = runScript("job/exampleJob.jenkins") 29 | script.execute() 30 | printCallStack() 31 | assertJobStatusSuccess() 32 | } 33 | 34 | @Test 35 | void should_print_property_value() { 36 | def script = runScript('job/exampleJob.jenkins') 37 | script.execute() 38 | 39 | def value = 'value' 40 | assertTrue(helper.callStack.findAll { call -> 41 | call.methodName == 'println' 42 | }.any { call -> 43 | callArgsToString(call).contains(value) 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestFailingJobs.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) by Courtanet, All Rights Reserved. 3 | */ 4 | package com.lesfurets.jenkins 5 | 6 | import org.codehaus.groovy.runtime.typehandling.GroovyCastException 7 | import org.junit.Before 8 | import org.junit.Ignore 9 | import org.junit.Test 10 | 11 | import com.lesfurets.jenkins.unit.cps.BasePipelineTestCPS; 12 | 13 | class TestFailingJobs extends BasePipelineTestCPS { 14 | 15 | @Override 16 | @Before 17 | void setUp() throws Exception { 18 | scriptRoots += 'src/test/jenkins' 19 | super.setUp() 20 | } 21 | 22 | @Test(expected = GroovyCastException) 23 | void should_fail_nonCpsCallingCps() throws Exception { 24 | def script = runScript("job/shouldFail/nonCpsCallingCps.jenkins") 25 | printCallStack() 26 | } 27 | 28 | /** 29 | * java.lang.UnsupportedOperationException: Calling public static java.util.List 30 | * org.codehaus.groovy.runtime.DefaultGroovyMethods.each(java.util.List,groovy.lang.Closure) 31 | * on a CPS-transformed closure is not yet supported (JENKINS-26481); 32 | * encapsulate in a @NonCPS method, or use Java-style loops 33 | */ 34 | @Test(expected = UnsupportedOperationException) 35 | @Ignore 36 | void should_fail_forEach() throws Exception { 37 | def script = runScript("job/shouldFail/forEach.jenkins") 38 | printCallStack() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestHelperInitialization.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Test 4 | 5 | import com.lesfurets.jenkins.unit.BasePipelineTest 6 | 7 | class TestHelperInitialization extends BasePipelineTest { 8 | 9 | @Test(expected = IllegalStateException) 10 | void non_initialized_helper() throws Exception { 11 | runScript('jobs/exampleJob.jenkins') 12 | } 13 | 14 | @Test(expected = NullPointerException) 15 | void non_initialized_gse() throws Exception { 16 | helper.loadScript('jobs/exampleJob.jenkins') 17 | } 18 | 19 | @Test 20 | void initialized_helper() throws Exception { 21 | scriptRoots += 'src/test/jenkins' 22 | super.setUp() 23 | helper.loadScript('job/exampleJob.jenkins') 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestHelperSingleton.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import com.lesfurets.jenkins.unit.PipelineTestHelper 5 | import org.junit.Before 6 | import org.junit.BeforeClass 7 | import org.junit.Test 8 | 9 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 10 | import static com.lesfurets.jenkins.unit.global.lib.LocalSource.localSource 11 | import static org.assertj.core.api.Assertions.assertThat 12 | 13 | class TestHelperSingleton extends BasePipelineTest { 14 | 15 | static PipelineTestHelper HELPER = new PipelineTestHelper() 16 | 17 | TestHelperSingleton() { 18 | super(HELPER) 19 | } 20 | 21 | @Override 22 | @Before 23 | void setUp() throws Exception { 24 | scriptRoots += 'src/test/jenkins' 25 | 26 | String sharedLibs = this.class.getResource('/libs').getFile() 27 | 28 | def library = library().name('commons') 29 | .defaultVersion("master") 30 | .allowOverride(true) 31 | .implicit(true) 32 | .targetPath(sharedLibs) 33 | .retriever(localSource(sharedLibs)) 34 | .build() 35 | 36 | HELPER.registerSharedLibrary(library) 37 | 38 | super.setUp() 39 | } 40 | 41 | @Test 42 | void staticHelperTestRunScript() throws Exception { 43 | 44 | assertThat(helper.isInitialized()) 45 | 46 | assertThat(helper == HELPER) 47 | 48 | boolean exception = false 49 | try { 50 | def script = runScript("job/library/libraryJob.jenkins") 51 | script.execute() 52 | printCallStack() 53 | } catch (e) { 54 | e.printStackTrace() 55 | exception = true 56 | } 57 | assertThat(false).isEqualTo(exception) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestInlineScript.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 4 | import static com.lesfurets.jenkins.unit.global.lib.LocalSource.localSource 5 | 6 | import org.junit.Before 7 | import org.junit.Test 8 | 9 | import com.lesfurets.jenkins.unit.BasePipelineTest 10 | 11 | class TestInlineScript extends BasePipelineTest { 12 | 13 | String sharedLibs = this.class.getResource('/libs').getFile() 14 | 15 | @Override 16 | @Before 17 | void setUp() throws Exception { 18 | scriptRoots += 'src/test/jenkins' 19 | super.setUp() 20 | 21 | def library = library() 22 | .name('commons') 23 | .defaultVersion('master') 24 | .allowOverride(true) 25 | .implicit(false) 26 | .targetPath(sharedLibs) 27 | .retriever(localSource(sharedLibs)) 28 | .build() 29 | 30 | helper.registerSharedLibrary(library) 31 | } 32 | 33 | @Test 34 | void load_inline_script_with_simple_commands() { 35 | def script = loadInlineScript(''' 36 | node { 37 | echo 'Test' 38 | } 39 | ''') 40 | 41 | script.run() 42 | 43 | printCallStack() 44 | assertJobStatusSuccess() 45 | } 46 | 47 | @Test 48 | void run_inline_script_with_simple_commands() { 49 | runInlineScript(''' 50 | node { 51 | echo 'Test' 52 | } 53 | ''') 54 | 55 | printCallStack() 56 | assertJobStatusSuccess() 57 | } 58 | 59 | @Test 60 | void load_inline_script_with_shared_library() { 61 | def script = loadInlineScript(''' 62 | @Library('commons') _ 63 | 64 | node { 65 | sayHello() 66 | } 67 | ''') 68 | 69 | script.run() 70 | 71 | printCallStack() 72 | assertJobStatusSuccess() 73 | } 74 | 75 | @Test 76 | void run_inline_script_with_shared_library() { 77 | runInlineScript(''' 78 | @Library('commons') _ 79 | 80 | node { 81 | sayHello() 82 | } 83 | ''') 84 | 85 | printCallStack() 86 | assertJobStatusSuccess() 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestInterceptingGCLLazyLoadLibClasses.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.LibClassLoader 4 | import com.lesfurets.jenkins.unit.BasePipelineTest 5 | 6 | import org.junit.Before 7 | import org.junit.Test 8 | 9 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 10 | import static com.lesfurets.jenkins.unit.global.lib.ProjectSource.projectSource 11 | 12 | class TestInterceptingGCLLazyLoadLibClasses extends BasePipelineTest { 13 | @Override 14 | @Before 15 | void setUp() throws Exception { 16 | scriptRoots += 'src/test/jenkins' 17 | super.setUp() 18 | helper.libLoader.preloadLibraryClasses = false 19 | } 20 | 21 | /** 22 | * 1. Load two libraries--one dependent on the other--with implicity 23 | * 2. Create instance of library class and pass instance to library vars step 24 | * 3. That vars step in turn creates instance of another library class 25 | * and passes it to another library step 26 | * 4. Make sure interception of pipeline methods works propertly 27 | */ 28 | @Test 29 | void test_cross_class_as_var_arg_implicit_lazy_load() throws Exception { 30 | //This does not factor much in the current test but does replicate the 31 | //use case in which the lazy load feature originated. 32 | helper.cloneArgsOnMethodCallRegistration = false 33 | 34 | //test_cross_class_as_var_arg_1 uses vars and classes in 35 | //test_cross_class_as_var_arg_2 so the latter has to be loaded first 36 | [ 37 | "test_cross_class_as_var_arg_2", 38 | "test_cross_class_as_var_arg_1", 39 | ].each { libName -> 40 | final libDir = this.class.getResource("/libs/$libName").file 41 | final library = library().name(libName) 42 | .defaultVersion("master") 43 | .allowOverride(false) 44 | .implicit(true) 45 | .targetPath(libDir) 46 | .retriever(projectSource(libDir)) 47 | .build() 48 | helper.registerSharedLibrary(library) 49 | } 50 | 51 | final pipeline = "test_var_with_lib_class_arg" 52 | runScript("job/library/cross_class_lazy_load/${pipeline}.jenkins") 53 | printCallStack() 54 | assertCallStackContains("""${pipeline}.monster1(org.test.Monster1""") 55 | assertCallStackContains("""monster1.monster2(org.test.extra.Monster2""") 56 | assertCallStackContains("""monster2.echo(Frankenstein's Monster all by itself is frightening)""") 57 | assertCallStackContains("""monster1.echo(Dracula and Frankenstein's Monster make quite a scary team)""") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestOneArgumentJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 4 | import static com.lesfurets.jenkins.unit.global.lib.LocalSource.localSource 5 | 6 | import com.lesfurets.jenkins.unit.LibClassLoader 7 | import com.lesfurets.jenkins.unit.BaseRegressionTest 8 | import org.junit.Before 9 | import org.junit.Test 10 | 11 | import static org.junit.Assert.assertTrue 12 | 13 | class TestOneArgumentJob extends BaseRegressionTest { 14 | 15 | String sharedLibs = this.class.getResource('/libs').getFile() 16 | 17 | @Override 18 | @Before 19 | void setUp() throws Exception { 20 | scriptRoots += 'src/test/jenkins' 21 | super.setUp() 22 | binding.setVariable('scm', [branch: 'master']) 23 | } 24 | 25 | @Test 26 | void should_run_script_with_one_argument() { 27 | def library = library().name('commons') 28 | .defaultVersion("master") 29 | .allowOverride(true) 30 | .implicit(false) 31 | .targetPath(sharedLibs) 32 | .retriever(localSource(sharedLibs)) 33 | .build() 34 | helper.registerSharedLibrary(library) 35 | 36 | // when: 37 | runScript("job/library/test_lib_call_with_null.jenkins") 38 | 39 | // then: 40 | assertJobStatusSuccess() 41 | testNonRegression("should_run_script_with_one_argument") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestParallelJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BasePipelineTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | class TestParallelJob extends BasePipelineTest { 8 | 9 | @Override 10 | @Before 11 | void setUp() throws Exception { 12 | scriptRoots += 'src/test/jenkins' 13 | super.setUp() 14 | def scmBranch = "feature_test" 15 | binding.setVariable('scm', [ 16 | $class : 'GitSCM', 17 | branches : [[name: scmBranch]], 18 | extensions : [], 19 | userRemoteConfigs : [[ 20 | credentialsId: 'gitlab_git_ssh', 21 | url : 'github.com/lesfurets/JenkinsPipelineUnit.git' 22 | ]] 23 | ]) 24 | } 25 | 26 | @Test 27 | void should_execute_parallel_with_errors() throws Exception { 28 | def script = runScript("job/parallelJob.jenkins") 29 | try{ 30 | script.execute() 31 | } finally { 32 | printCallStack() 33 | } 34 | assertJobStatusFailure() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestParallelJobCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import com.lesfurets.jenkins.unit.cps.BasePipelineTestCPS 7 | 8 | class TestParallelJobCPS extends BasePipelineTestCPS { 9 | 10 | @Override 11 | @Before 12 | void setUp() throws Exception { 13 | scriptRoots += 'src/test/jenkins' 14 | super.setUp() 15 | def scmBranch = "feature_test" 16 | binding.setVariable('scm', [ 17 | $class : 'GitSCM', 18 | branches : [[name: scmBranch]], 19 | extensions : [], 20 | userRemoteConfigs : [[ 21 | credentialsId: 'gitlab_git_ssh', 22 | url : 'github.com/lesfurets/JenkinsPipelineUnit.git' 23 | ]] 24 | ]) 25 | } 26 | 27 | @Test 28 | void should_execute_parallel_with_errors() throws Exception { 29 | def script = runScript("job/parallelJob.jenkins") 30 | try{ 31 | script.execute() 32 | } finally { 33 | printCallStack() 34 | } 35 | assertJobStatusFailure() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestParametersJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BaseRegressionTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | class TestParametersJob extends BaseRegressionTest { 8 | 9 | @Override 10 | @Before 11 | void setUp() throws Exception { 12 | scriptRoots += 'src/test/jenkins' 13 | super.setUp() 14 | } 15 | 16 | @Test 17 | void should_run_script_parameters() { 18 | // when: 19 | runScript("job/parameters.jenkins") 20 | 21 | // then: 22 | assertJobStatusSuccess() 23 | testNonRegression("parameters") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestRegisterOriginalMethodCallArgs.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import com.lesfurets.jenkins.unit.BasePipelineTest 7 | 8 | import static org.junit.Assert.* 9 | 10 | class TestRegisterOriginalMethodCallArgs extends BasePipelineTest { 11 | 12 | @Override 13 | @Before 14 | void setUp() throws Exception { 15 | scriptRoots += "src/test/jenkins" 16 | super.setUp() 17 | } 18 | 19 | @Test 20 | void should_not_always_clone_args() { 21 | helper.cloneArgsOnMethodCallRegistration = false 22 | 23 | runScript("job/immutableMapArgs.jenkins") 24 | 25 | def arg = helper.callStack.find { call -> 26 | call.methodName == "writeFile" 27 | }.args.first() 28 | 29 | //Ensure that the arg is the original uncloned binding variable, and 30 | //that we can inspect it in detail using all the normal Map interfaces. 31 | assertTrue(arg.is(binding.pretendArgsFromFarUpstream)) 32 | 33 | assertEquals(arg.getClass().simpleName, "UnmodifiableMap") 34 | assertEquals(arg.size(), 2) 35 | 36 | assertEquals(arg.file, "foo.txt") 37 | assertEquals(arg.text, "All bar, all the time") 38 | } 39 | 40 | @Test 41 | void should_usually_clone_args() { 42 | //By default the helper clones args on registering calls. 43 | 44 | runScript("job/immutableMapArgs.jenkins") 45 | 46 | def arg = helper.callStack.find { call -> 47 | call.methodName == "writeFile" 48 | }.args.first() 49 | 50 | //Ensure that the arg is not the original binding variable, and not 51 | //even the same type, because that variable was an uncloneable 52 | //UnmodifiableMap. The cloning logic turns uncloneables into Strings. 53 | assertFalse(arg.is(binding.pretendArgsFromFarUpstream)) 54 | 55 | assertEquals(arg.getClass().simpleName, "String") 56 | 57 | assertTrue(arg.contains("file:foo.txt") || arg.contains("file=foo.txt")) 58 | assertTrue(arg.contains("text:All bar, all the time") || arg.contains("text=All bar, all the time")) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestRegression.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import com.lesfurets.jenkins.unit.cps.BaseRegressionTestCPS 7 | 8 | class TestRegression extends BaseRegressionTestCPS { 9 | 10 | @Override 11 | @Before 12 | void setUp() throws Exception { 13 | scriptRoots += 'src/test/jenkins' 14 | super.setUp() 15 | def scmBranch = "feature_test" 16 | helper.registerAllowedMethod("sh", [Map.class], {c -> 'bcc19744'}) 17 | binding.setVariable('scm', [ 18 | $class : 'GitSCM', 19 | branches : [[name: scmBranch]], 20 | extensions : [], 21 | userRemoteConfigs : [[ 22 | credentialsId: 'gitlab_git_ssh', 23 | url : 'github.com/lesfurets/JenkinsPipelineUnit.git' 24 | ]] 25 | ]) 26 | } 27 | 28 | @Test 29 | void testNonReg() throws Exception { 30 | def script = runScript("job/exampleJob.jenkins") 31 | script.execute() 32 | super.testNonRegression("example") 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestRegressionGlobalVar.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.cps.BaseRegressionTestCPS 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | class TestRegressionGlobalVar extends BaseRegressionTestCPS { 8 | 9 | @Override 10 | @Before 11 | void setUp() throws Exception { 12 | scriptRoots += 'src/test/jenkins' 13 | super.setUp() 14 | helper.registerAllowedMethod("doWithProperties", [TreeMap.class], null) 15 | } 16 | 17 | @Test 18 | void testGlobalVarRegression() throws Exception { 19 | runScript("job/globalVar.jenkins") 20 | super.testNonRegression("globalVar") 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSerialization.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import com.lesfurets.jenkins.unit.BasePipelineTest 7 | 8 | class TestSerialization extends BasePipelineTest { 9 | 10 | @Override 11 | @Before 12 | void setUp() throws Exception { 13 | scriptRoots += 'src/test/jenkins' 14 | super.setUp() 15 | def scmBranch = "feature_test" 16 | binding.setVariable('scm', [ 17 | $class : 'GitSCM', 18 | branches : [[name: scmBranch]], 19 | extensions : [], 20 | userRemoteConfigs : [[ 21 | credentialsId: 'gitlab_git_ssh', 22 | url : 'github.com/lesfurets/JenkinsPipelineUnit.git' 23 | ]] 24 | ]) 25 | } 26 | 27 | /** 28 | * This exception should have thrown an exception because of the bad usage of NonCPS method. 29 | * @throws Exception 30 | */ 31 | @Test 32 | // (expected = Exception.class) 33 | void testException() throws Exception { 34 | def script = runScript('job/serialize.jenkins') 35 | try { 36 | script.execute() 37 | } catch (e) { 38 | throw e 39 | } finally { 40 | printCallStack() 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSerializationCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import com.lesfurets.jenkins.unit.cps.BasePipelineTestCPS 7 | 8 | class TestSerializationCPS extends BasePipelineTestCPS { 9 | 10 | 11 | 12 | @Override 13 | @Before 14 | void setUp() throws Exception { 15 | scriptRoots += 'src/test/jenkins' 16 | super.setUp() 17 | def scmBranch = "feature_test" 18 | binding.setVariable('scm', [ 19 | $class : 'GitSCM', 20 | branches : [[name: scmBranch]], 21 | extensions : [], 22 | userRemoteConfigs : [[ 23 | credentialsId: 'gitlab_git_ssh', 24 | url : 'github.com/lesfurets/JenkinsPipelineUnit.git' 25 | ]] 26 | ]) 27 | } 28 | 29 | @Test(expected = Exception.class) 30 | void testException() throws Exception { 31 | def script = loadScript('job/serialize.jenkins') 32 | try { 33 | script.execute() 34 | } catch (e) { 35 | throw e 36 | } finally { 37 | printCallStack() 38 | } 39 | } 40 | 41 | @Test 42 | void testSerialization() throws Exception { 43 | def script = runScript('job/serializeCPS.jenkins') 44 | try { 45 | script.execute() 46 | } catch (e) { 47 | throw e 48 | } finally { 49 | printCallStack() 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSharedLibraryAccessibleParams.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.declarative.DeclarativePipelineTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 8 | import static com.lesfurets.jenkins.unit.global.lib.ProjectSource.projectSource 9 | import static org.assertj.core.api.Assertions.assertThat 10 | 11 | class TestSharedLibraryAccessibleParams extends DeclarativePipelineTest { 12 | 13 | private final String JOB_NAME = "params_not_accessible" 14 | private final String JOB_PATH = "job/library/${JOB_NAME}.jenkins" 15 | private final String LIB_DIR = this.class.getResource("/libs/$JOB_NAME").getFile() 16 | private final String BINDING_VAR = "testVar" 17 | private final String BINDING_VAL = "notBroken" 18 | 19 | @Override 20 | @Before 21 | void setUp() throws Exception { 22 | scriptRoots += 'src/test/jenkins' 23 | super.setUp() 24 | def library = library().name(JOB_NAME) 25 | .retriever(projectSource(LIB_DIR)) 26 | .defaultVersion("master") 27 | .targetPath(LIB_DIR) 28 | .allowOverride(true) 29 | .implicit(false) 30 | .build() 31 | helper.registerSharedLibrary(library) 32 | } 33 | 34 | @Test 35 | void accessible_params_test() { 36 | run_test_with_bindings {assertJobStatusSuccess()} 37 | } 38 | 39 | @Test 40 | void change_binding_test() { 41 | run_test_with_bindings {assertThat(binding.getVariable(BINDING_VAR)).isNotEqualTo(BINDING_VAL)} 42 | } 43 | 44 | @Test(expected = MissingPropertyException.class) 45 | void not_accessible_params_test() { 46 | runScript(JOB_PATH) 47 | } 48 | 49 | private void run_test_with_bindings(Closure assertion) { 50 | binding.setVariable(BINDING_VAR, BINDING_VAL) 51 | runScript(JOB_PATH) 52 | assertion() 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSharedLibraryEnvVariable.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.declarative.DeclarativePipelineTest 4 | import org.junit.Assert 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 9 | import static com.lesfurets.jenkins.unit.global.lib.ProjectSource.projectSource 10 | 11 | class TestSharedLibraryEnvVariable extends DeclarativePipelineTest { 12 | 13 | String sharedLibVars = this.class.getResource("/libs/env_var_not_defined").getFile() 14 | 15 | @Override 16 | @Before 17 | void setUp() throws Exception { 18 | scriptRoots += 'src/test/jenkins' 19 | 20 | super.setUp() 21 | 22 | def library = library().name("env_var_not_defined") 23 | .retriever(projectSource(sharedLibVars)) 24 | .defaultVersion("master") 25 | .targetPath(sharedLibVars) 26 | .allowOverride(true) 27 | .implicit(false) 28 | .build() 29 | helper.registerSharedLibrary(library) 30 | } 31 | 32 | @Test 33 | void "test lib var not defined in env"() { 34 | 35 | runScript("job/library/test_lib_var_not_defined_in_env.jenkins") 36 | 37 | def prop1 = binding.env["prop1"] 38 | Assert.assertEquals("magic", prop1) 39 | } 40 | 41 | @Test 42 | void "test params not defined in env"() { 43 | runScript("job/library/test_params_not_defined_in_env.jenkins") 44 | 45 | def versionFromEnv = binding.env["VERSION"] 46 | def versionFromParams = binding.params["VERSION"] 47 | Assert.assertEquals(versionFromParams.toString(), versionFromEnv.toString()) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSharedLibraryWithLocalSourceRetriever.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.LibClassLoader 4 | 5 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 6 | import static com.lesfurets.jenkins.unit.global.lib.LocalSource.localSource 7 | import static org.assertj.core.api.Assertions.assertThat 8 | 9 | import org.junit.Before 10 | import org.junit.Rule 11 | import org.junit.Test 12 | import org.junit.rules.TemporaryFolder 13 | import org.junit.runner.RunWith 14 | import org.junit.runners.Parameterized 15 | import org.junit.runners.Parameterized.Parameter 16 | import org.junit.runners.Parameterized.Parameters 17 | 18 | import com.lesfurets.jenkins.unit.BasePipelineTest 19 | 20 | @RunWith(Parameterized.class) 21 | class TestSharedLibrary extends BasePipelineTest { 22 | 23 | @Rule 24 | public TemporaryFolder folder = new TemporaryFolder() 25 | 26 | String sharedLibs = this.class.getResource('/libs').getFile() 27 | 28 | @Parameter(0) 29 | public String script 30 | @Parameter(1) 31 | public boolean allowOverride 32 | @Parameter(2) 33 | public boolean implicit 34 | @Parameter(3) 35 | public boolean expected 36 | 37 | @Override 38 | @Before 39 | void setUp() throws Exception { 40 | scriptRoots += 'src/test/jenkins' 41 | super.setUp() 42 | binding.setVariable('scm', [branch: 'master']) 43 | } 44 | 45 | @Parameters(name = "Test {0} allowOverride:{1} implicit:{2} expected:{3}") 46 | static Collection data() { 47 | return [['libraryJob', false, false, false], 48 | ['libraryJob_implicit', false, false, true], 49 | ['libraryJob_implicit', false, true, false], 50 | ['libraryJob_master', true, false, false], 51 | ['libraryJob_master', false, false, false], 52 | ['libraryJob_feature', true, false, false], 53 | ['libraryJob_feature', false, false, true], 54 | ['libraryJob_feature2', true, false, true], 55 | ['libraryJob_inline_library', false, false, true], 56 | ['libraryJob_dynamic_map', false, false, false], 57 | ].collect { it as Object[] } 58 | } 59 | 60 | @Test 61 | void library_annotation() throws Exception { 62 | boolean exception = false 63 | def library = library().name('commons') 64 | .defaultVersion("master") 65 | .allowOverride(allowOverride) 66 | .implicit(implicit) 67 | .targetPath(sharedLibs) 68 | .retriever(localSource(sharedLibs)) 69 | .build() 70 | helper.registerSharedLibrary(library) 71 | try { 72 | def script = loadScript("job/library/${script}.jenkins") 73 | script.execute() 74 | printCallStack() 75 | } catch (e) { 76 | e.printStackTrace() 77 | exception = true 78 | } 79 | assertThat(expected).isEqualTo(exception) 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSharedLibraryWithLocalSourceRetrieverCPS.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 4 | import static com.lesfurets.jenkins.unit.global.lib.LocalSource.localSource 5 | import static org.assertj.core.api.Assertions.assertThat 6 | 7 | import org.junit.Before 8 | import org.junit.Rule 9 | import org.junit.Test 10 | import org.junit.rules.TemporaryFolder 11 | import org.junit.runner.RunWith 12 | import org.junit.runners.Parameterized 13 | import org.junit.runners.Parameterized.Parameter 14 | import org.junit.runners.Parameterized.Parameters 15 | 16 | import com.lesfurets.jenkins.unit.cps.BasePipelineTestCPS 17 | 18 | @RunWith(Parameterized.class) 19 | class TestSharedLibraryCPS extends BasePipelineTestCPS { 20 | 21 | @Rule 22 | public TemporaryFolder folder = new TemporaryFolder() 23 | 24 | String sharedLibs = this.class.getResource('/libs').getFile() 25 | 26 | @Parameter(0) 27 | public String script 28 | @Parameter(1) 29 | public boolean allowOverride 30 | @Parameter(2) 31 | public boolean implicit 32 | @Parameter(3) 33 | public boolean expected 34 | 35 | @Override 36 | @Before 37 | void setUp() throws Exception { 38 | scriptRoots += 'src/test/jenkins' 39 | super.setUp() 40 | binding.setVariable('scm', [branch: 'master']) 41 | } 42 | 43 | @Parameters(name = "Test {0} allowOverride:{1} implicit:{2} expected:{3}") 44 | static Collection data() { 45 | return [['libraryJob', false, false, false], 46 | ['libraryJob_implicit', false, false, true], 47 | ['libraryJob_implicit', false, true, false], 48 | ['libraryJob_master', true, false, false], 49 | ['libraryJob_master', false, false, false], 50 | ['libraryJob_feature', true, false, false], 51 | ['libraryJob_feature', false, false, true], 52 | ['libraryJob_feature2', true, false, true], 53 | ['libraryJob_inline_library', false, false, true], 54 | ].collect { it as Object[] } 55 | } 56 | 57 | @Test 58 | void library_annotation() throws Exception { 59 | boolean exception = false 60 | def library = library().name('commons') 61 | .defaultVersion("master") 62 | .allowOverride(allowOverride) 63 | .implicit(implicit) 64 | .targetPath(sharedLibs) 65 | .retriever(localSource(sharedLibs)) 66 | .build() 67 | helper.registerSharedLibrary(library) 68 | try { 69 | def script = runScript("job/library/${script}.jenkins") 70 | script.execute() 71 | printCallStack() 72 | } catch (e) { 73 | e.printStackTrace() 74 | exception = true 75 | } 76 | assertThat(exception).isEqualTo(expected) 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestSharedLibraryWithProjectSourceRetriever.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library 4 | import static com.lesfurets.jenkins.unit.global.lib.ProjectSource.projectSource 5 | import static org.assertj.core.api.Assertions.assertThat 6 | 7 | import org.junit.Before 8 | import org.junit.Rule 9 | import org.junit.Test 10 | import org.junit.rules.TemporaryFolder 11 | import org.junit.runner.RunWith 12 | import org.junit.runners.Parameterized 13 | import org.junit.runners.Parameterized.Parameter 14 | import org.junit.runners.Parameterized.Parameters 15 | 16 | import com.lesfurets.jenkins.unit.BasePipelineTest 17 | 18 | @RunWith(Parameterized.class) 19 | class TestSharedLibraryWithProjectSourceRetriever extends BasePipelineTest { 20 | 21 | // For simplicity we use the common@master here. In this case 'commons@master' 22 | // does not denote the master branch of the commons lib. In this case it is 23 | // just a folder containing the lib. ProjectSourceRetriever is by design 24 | // agnostic to branches and agnostic to library names. 25 | // By default ProjectSourceRetriever works upon '.', which is the project 26 | // root directory. Here for testing the retriever is used in a way so that 27 | // it refers to the folder mentioned below. 28 | String sharedLibs = this.class.getResource('/libs/commons@master').getFile() 29 | 30 | @Parameter(0) 31 | public String script 32 | @Parameter(1) 33 | public boolean allowOverride 34 | @Parameter(2) 35 | public boolean implicit 36 | @Parameter(3) 37 | public boolean expected 38 | 39 | @Override 40 | @Before 41 | void setUp() throws Exception { 42 | scriptRoots += 'src/test/jenkins' 43 | super.setUp() 44 | } 45 | 46 | @Parameters(name = "Test {0} allowOverride:{1} implicit:{2} expected:{3}") 47 | static Collection data() { 48 | return [['libraryJob', false, false, false], 49 | ['libraryJob_implicit', false, false, true], 50 | ['libraryJob_implicit', false, true, false], 51 | 52 | // Utils2, denoted in the job below, cannot be resolved 53 | // since we do not have the lib from the feature branch 54 | // despite this is requested in the pipeline. 55 | // ProjectSourceRetriever does by design 56 | // not take branches into account. 57 | ['libraryJob_feature', true, true, true], 58 | 59 | ].collect { it as Object[] } 60 | } 61 | 62 | @Test 63 | void library_annotation() throws Exception { 64 | boolean exception = false 65 | def library = library().name('commons') 66 | .defaultVersion('') 67 | .allowOverride(allowOverride) 68 | .implicit(implicit) 69 | .targetPath('') 70 | .retriever(projectSource(sharedLibs)) 71 | .build() 72 | helper.registerSharedLibrary(library) 73 | try { 74 | def script = runScript("job/library/${script}.jenkins") 75 | script.execute() 76 | printCallStack() 77 | } catch (e) { 78 | e.printStackTrace() 79 | exception = true 80 | } 81 | assertThat(expected).isEqualTo(exception) 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestWithCredentialsAndParametersJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BaseRegressionTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | class TestWithCredentialsAndParametersJob extends BaseRegressionTest { 8 | 9 | @Override 10 | @Before 11 | void setUp() throws Exception { 12 | scriptRoots += 'src/test/jenkins' 13 | super.setUp() 14 | } 15 | 16 | @Test 17 | void should_run_script_with_parameters() { 18 | // when: 19 | runScript("job/withCredentialsAndParameters.jenkins") 20 | 21 | // then: 22 | assertJobStatusSuccess() 23 | testNonRegression("withCredentialsAndParameters") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/TestWithCredentialsJob.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins 2 | 3 | import com.lesfurets.jenkins.unit.BaseRegressionTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | import static org.junit.Assert.assertTrue 8 | 9 | class TestWithCredentialsJob extends BaseRegressionTest { 10 | 11 | @Override 12 | @Before 13 | void setUp() throws Exception { 14 | scriptRoots += 'src/test/jenkins' 15 | super.setUp() 16 | } 17 | 18 | @Test 19 | void should_run_script_with_credentials() { 20 | // when: 21 | runScript("job/withCredentials.jenkins") 22 | 23 | // then: 24 | assertJobStatusSuccess() 25 | testNonRegression("withCredentials") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/unit/BasePipelineTestTest.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | import static org.assertj.core.api.Assertions.assertThat 4 | 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class BasePipelineTestTest extends BasePipelineTest { 9 | @Before 10 | @Override 11 | void setUp() throws Exception { 12 | scriptRoots += 'src/test/jenkins/jenkinsfiles' 13 | scriptExtension = '' 14 | super.setUp() 15 | } 16 | 17 | @Test 18 | void buildStatusFailure() { 19 | runScript('BuildStatus_Failure_Jenkinsfile') 20 | assertThat(binding.getVariable('currentBuild').result).isEqualTo('FAILURE') 21 | assertThat(binding.getVariable('currentBuild').currentResult).isEqualTo('FAILURE') 22 | } 23 | 24 | @Test 25 | void buildStatusSuccess() { 26 | runScript('BuildStatus_Success_Jenkinsfile') 27 | assertThat(binding.getVariable('currentBuild').result).isEqualTo('SUCCESS') 28 | assertThat(binding.getVariable('currentBuild').currentResult).isEqualTo('SUCCESS') 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/unit/CallStackDumpTest.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | import org.junit.Test 4 | 5 | class CallStackDumpTest extends BasePipelineTest { 6 | 7 | @Test 8 | void test_callStackDump_returns_new_value() { 9 | setUp() 10 | def script = loadScript('src/test/jenkins/job/callStackDump.jenkins') 11 | 12 | // Call method1 and expect callstack to match 13 | script.someMethod1() 14 | assertCallStackContains('callStackDump.someMethod1()') 15 | 16 | // Reset using setUp call 17 | setUp() 18 | // Call method2 and expect callstack to match 19 | script.someMethod2() 20 | assertCallStackContains('callStackDump.someMethod2()') 21 | assertCallStack().doesNotContain('callStackDump.someMethod1()') 22 | 23 | // Reset using clearCallStack call 24 | clearCallStack() 25 | // Call method1 and expect callstack to match 26 | script.someMethod1() 27 | assertCallStackContains('callStackDump.someMethod1()') 28 | } 29 | 30 | @Test 31 | void test_callStackDump_returns_cached_value() { 32 | setUp() 33 | def script = loadScript('src/test/jenkins/job/callStackDump.jenkins') 34 | 35 | // Call method1 and expect callstack to match 36 | script.someMethod1() 37 | assertCallStackContains('callStackDump.someMethod1()') 38 | assertCallStack().doesNotContain('callStackDump.someMethod2()') 39 | 40 | // Do not clear call stack continue your test 41 | 42 | // Call method2 and expect callstack to match 43 | script.someMethod2() 44 | assertCallStackContains('callStackDump.someMethod1()') 45 | assertCallStackContains('callStackDump.someMethod2()') 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/unit/VerifyTest.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | class VerifyTest extends BasePipelineTest { 7 | 8 | static final String PARAMETER1 = "someString" 9 | static final String PARAMETER2 = "anotherString" 10 | static final String SOME_STRING_METHOD_NAME = "someStringMethod" 11 | static final String VOID_METHOD_NAME = "voidMethod" 12 | 13 | Script script 14 | 15 | @Before 16 | void beforeTest() { 17 | setUp() 18 | script = loadScript('src/test/jenkins/job/verify.jenkins') 19 | } 20 | 21 | @Test 22 | void verify_some_string_method() { 23 | script.someStringMethod(PARAMETER1) 24 | script.someStringMethod(PARAMETER1, PARAMETER2) 25 | helper.verify(SOME_STRING_METHOD_NAME, 2) 26 | } 27 | 28 | @Test 29 | void verify_some_string_method_parameter1() { 30 | script.someStringMethod(PARAMETER1) 31 | helper.verify(SOME_STRING_METHOD_NAME, 1) { methodCall -> 32 | return methodCall.args[0].toString() == PARAMETER1 33 | } 34 | } 35 | 36 | @Test 37 | void verify_some_string_method_parameter2() { 38 | script.someStringMethod(PARAMETER1, PARAMETER2) 39 | helper.verify(SOME_STRING_METHOD_NAME, 1) { methodCall -> 40 | Object[] arguments = methodCall.args 41 | return arguments.size() == 2 && arguments[0].toString() == PARAMETER1 && arguments[1].toString() == PARAMETER2 42 | } 43 | } 44 | 45 | @Test(expected = VerificationException.class) 46 | void verify_some_string_method_another_params() { 47 | script.someStringMethod(PARAMETER1, "another") 48 | helper.verify(SOME_STRING_METHOD_NAME, 1) { MethodCall methodCall -> 49 | Object[] arguments = methodCall.args 50 | return arguments.size() == 2 && arguments[0].toString() == PARAMETER1 && arguments[1].toString() == PARAMETER2 51 | } 52 | } 53 | 54 | @Test 55 | void verify_void_method() { 56 | script.voidMethod() 57 | helper.verify(VOID_METHOD_NAME) 58 | } 59 | 60 | @Test(expected = VerificationException.class) 61 | void verify_void_method_expect_param() { 62 | script.voidMethod() 63 | helper.verify(VOID_METHOD_NAME, 1) { methodCall -> methodCall.args.size() > 0 } 64 | } 65 | 66 | @Test(expected = VerificationException.class) 67 | void verify_void_method_less_times() { 68 | script.voidMethod() 69 | script.voidMethod() 70 | helper.verify(VOID_METHOD_NAME) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestDeclaraticeWithCredentials.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import com.lesfurets.jenkins.unit.declarative.DeclarativePipelineTest 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | import static org.junit.Assert.assertTrue 8 | 9 | class TestDeclaraticeWithCredentials extends DeclarativePipelineTest { 10 | 11 | @Override 12 | @Before 13 | void setUp() throws Exception { 14 | scriptRoots += 'src/test/jenkins/jenkinsfiles' 15 | scriptExtension = '' 16 | super.setUp() 17 | } 18 | 19 | @Test 20 | void should_run_script_with_credentials() { 21 | // when: 22 | runScript("withCredentials_Jenkinsfile") 23 | 24 | // then: 25 | assertJobStatusSuccess() 26 | assertCallStack().contains("echo(User/Pass = user/pass)") 27 | assertCallStack().contains("echo(Nested User/Pass = user/pass)") 28 | assertCallStack().contains("echo(Restored User/Pass = user/pass)") 29 | assertCallStack().contains("echo(Cleared User/Pass = null/null)") 30 | 31 | assertCallStack().contains("echo(Docker = docker_pass)") 32 | assertCallStack().contains("echo(Nested Docker = docker_pass)") 33 | assertCallStack().contains("echo(Restored Docker = docker_pass)") 34 | assertCallStack().contains("echo(Cleared Docker = null)") 35 | 36 | assertCallStack().contains("echo(SSH = ssh_pass)") 37 | assertCallStack().contains("echo(Nested SSH = ssh_pass)") 38 | assertCallStack().contains("echo(Restored SSH = ssh_pass)") 39 | assertCallStack().contains("echo(Cleared SSH = null)") 40 | 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestDockerAgentInStep.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | class TestDockerAgentInStep extends DeclarativePipelineTest { 7 | 8 | @Before 9 | @Override 10 | void setUp() throws Exception { 11 | scriptRoots += 'src/test/jenkins/jenkinsfiles' 12 | scriptExtension = '' 13 | super.setUp() 14 | } 15 | 16 | @Test 17 | void test_example() { 18 | runScript("Docker_agentInStep_JenkinsFile") 19 | assertJobStatusSuccess() 20 | } 21 | 22 | @Test 23 | void test_dockerfile_agent() { 24 | runScript("Dockerfile_agent_JenkinsFile") 25 | assertJobStatusSuccess() 26 | } 27 | 28 | @Test 29 | void test_dockerfile_agent_only_filename_specified() { 30 | runScript("Dockerfile_Agent_Only_Filename_JenkinsFile") 31 | assertCallStackContains('Executing on agent [dockerfile') 32 | assertJobStatusSuccess() 33 | } 34 | 35 | @Test void test_dockerfile_default_agent() throws Exception { 36 | runScript('Dockerfile_Agent_Default_Jenkinsfile') 37 | assertCallStackContains('Executing on agent [dockerfile') 38 | assertJobStatusSuccess() 39 | } 40 | 41 | @Test 42 | void test_docker_agent_callstack_does_not_contain_binding() { 43 | runScript("Docker_agentInStep_JenkinsFile") 44 | assertJobStatusSuccess() 45 | assertCallStack().doesNotContain('binding:groovy.lang.Binding@') 46 | assertCallStackContains('Docker_agentInStep_JenkinsFile.echo(Executing on agent [docker:[image:maven, reuseNode:false, stages:[:], args:, alwaysPull:true, containerPerStageRoot:false, label:latest]])') 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestMockLocalFunction.groovy: -------------------------------------------------------------------------------- 1 | package com.lesfurets.jenkins.unit.declarative 2 | 3 | import static org.assertj.core.api.Assertions.assertThat 4 | 5 | import org.junit.runners.JUnit4 6 | import com.lesfurets.jenkins.unit.InterceptingGCL 7 | import org.junit.Before 8 | import org.junit.Test 9 | 10 | class TestMockLocalFunction extends DeclarativePipelineTest { 11 | 12 | private static String SCRIPT_NO_PARAMS = "Mock_existing_function_Jenkinsfile" 13 | private static String SCRIPT_PARAMS = SCRIPT_NO_PARAMS + "_params" 14 | 15 | @Before 16 | @Override 17 | void setUp() throws Exception { 18 | scriptRoots += 'src/test/jenkins/jenkinsfiles' 19 | helper.registerAllowedMethod("githubNotify", [Map]) 20 | super.setUp() 21 | } 22 | 23 | @Test(expected=MissingMethodException.class) 24 | void no_params_should_execute_with_errors() { 25 | runScript(SCRIPT_NO_PARAMS) 26 | } 27 | 28 | @Test 29 | void no_params_should_execute_without_errors() { 30 | helper.registerAllowedMethod("runFunc") 31 | runScript(SCRIPT_NO_PARAMS) 32 | } 33 | 34 | @Test(expected=MissingMethodException.class) 35 | void params_should_execute_with_errors() { 36 | runScript(SCRIPT_PARAMS) 37 | } 38 | 39 | @Test 40 | void params_should_execute_without_errors() { 41 | helper.registerAllowedMethod("runFuncWithParam", [String]) 42 | runScript(SCRIPT_PARAMS) 43 | } 44 | 45 | @Test 46 | void default_closure_empty() { 47 | Class[] args = [] 48 | default_closure_parameter_check(args) 49 | } 50 | 51 | @Test 52 | void default_closure_different_args() { 53 | Class[] args = [Arrays.class, JUnit4.class, InterceptingGCL.class, String.class, Integer.class] 54 | default_closure_parameter_check(args) 55 | } 56 | 57 | @Test 58 | void default_closure_max_args() { 59 | Class[] args = (1..254).collect{ String.class } 60 | default_closure_parameter_check(args) 61 | } 62 | 63 | @Test(expected=IllegalArgumentException.class) 64 | void default_closure_exceeded_args() { 65 | Class[] args = (1..500).collect{ String.class } 66 | default_closure_parameter_check(args) 67 | } 68 | 69 | private static void default_closure_parameter_check(Class[] args) { 70 | Closure closure = InterceptingGCL.defaultClosure(args) 71 | assertThat(closure.getParameterTypes()).isEqualTo(args) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/lesfurets/jenkins/TestPipelineJava.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) by Courtanet, All Rights Reserved. 3 | */ 4 | package com.lesfurets.jenkins; 5 | 6 | import static com.lesfurets.jenkins.unit.MethodSignature.method; 7 | import static java.util.Arrays.stream; 8 | import static java.util.stream.Stream.concat; 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | import java.util.function.Consumer; 12 | import java.util.stream.Stream; 13 | 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | 17 | import com.lesfurets.jenkins.unit.BasePipelineTest; 18 | 19 | import groovy.lang.Script; 20 | 21 | public class TestPipelineJava extends BasePipelineTest { 22 | 23 | @Override 24 | @Before 25 | public void setUp() throws Exception { 26 | this.setScriptRoots(concat(stream(getScriptRoots()), Stream.of("src/test/jenkins")).toArray(String[]::new)); 27 | super.setUp(); 28 | Consumer println = System.out::println; 29 | getHelper().registerAllowedMethod(method("step", String.class), println); 30 | } 31 | 32 | @Test 33 | public void should_return_cleanname() throws Exception { 34 | Script script = (Script) loadScript("lib/utils.jenkins"); 35 | assertThat(script.invokeMethod("cleanName", new Object[] { "some thing"})).isEqualTo("SOME_THING"); 36 | printCallStack(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/AgentEmptyLabel_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { 3 | node { 4 | label '' 5 | customWorkspace "myworkspace" 6 | } 7 | } 8 | stages { 9 | stage('Example Build') { 10 | steps { 11 | echo "Hello using custom workspace and empty label" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/AgentParam_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | parameters { 3 | booleanParam ( 4 | name: 'TOGGLE', 5 | defaultValue: true, 6 | description: 'Toggle this value' 7 | ) 8 | choice ( 9 | name: 'CHOICE', 10 | choices: ['One', 'Two', 'Three'], 11 | description: 'Pick something' 12 | ) 13 | password ( 14 | name: 'PASSWORD', 15 | defaultValue: 'SECRET', 16 | description: 'Enter a password' 17 | ) 18 | string ( 19 | name: 'AGENT', 20 | defaultValue: 'aSlave', 21 | description: 'The slave to use for testing tested.' 22 | ) 23 | text ( 24 | name: 'BIOGRAPHY', 25 | defaultValue: 'they were born, they lived, they died', 26 | description: 'Enter some information about the person' 27 | ) 28 | } 29 | agent { label params.AGENT } 30 | stages { 31 | stage('Example Build') { 32 | steps { 33 | echo "Hello from ${AGENT}" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/AgentStageNoSteps_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('A') { 5 | agent { label 'labelA' } 6 | post { always {echo 'post A'}} 7 | steps { 8 | echo 'A' 9 | } 10 | } 11 | stage('B') { 12 | agent {label 'labelB'} 13 | post { always {echo 'post B'}} 14 | stages { 15 | stage('C') { 16 | agent {label 'labelC'} 17 | post { always {echo 'post C'}} 18 | steps { 19 | echo 'C' 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Agent_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Example Build') { 5 | agent { docker 'maven:3-alpine' } 6 | steps { 7 | echo 'Hello, Maven' 8 | sh 'mvn --version' 9 | } 10 | } 11 | stage('Example Test') { 12 | agent { docker 'openjdk:8-jre' } 13 | steps { 14 | echo 'Hello, JDK' 15 | sh 'java -version' 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Agent_bindings_Jenkinsfile: -------------------------------------------------------------------------------- 1 | 2 | def AGENT = 'someLabel' 3 | 4 | pipeline { 5 | agent none 6 | stages { 7 | stage('Example Build') { 8 | agent binding_var 9 | steps { 10 | echo 'Hello, Maven' 11 | sh 'mvn --version' 12 | } 13 | } 14 | stage('Example Test') { 15 | agent { docker binding_var } 16 | steps { 17 | echo 'Hello, JDK' 18 | sh 'java -version' 19 | } 20 | } 21 | stage('Example Release') { 22 | agent agentName() 23 | steps { 24 | echo "Deploy to ${AGENT}" 25 | } 26 | } 27 | stage('Example Deploy') { 28 | agent AGENT 29 | steps { 30 | echo "Deploy to ${AGENT}" 31 | } 32 | } 33 | } 34 | } 35 | private String agentName(){ 36 | return 'someLabel'; 37 | } 38 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Agent_env_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Example Build') { 5 | agent env.ENV_VAR.toString() 6 | steps { 7 | echo 'Hello, Maven' 8 | sh 'mvn --version' 9 | } 10 | } 11 | stage('Example Test') { 12 | agent { docker env.some_env_var } 13 | steps { 14 | echo 'Hello, JDK' 15 | sh 'java -version' 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/AllOf_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example allOf expression') { 10 | when { 11 | allOf { 12 | expression { 13 | return env.SHOULD_EXECUTE == 'true' 14 | } 15 | expression { 16 | return env.SHOULD_ALSO_EXECUTE == 'true' 17 | } 18 | } 19 | } 20 | steps { 21 | echo 'Executing allOf with expression' 22 | } 23 | } 24 | stage('Example allOf branches') { // Contrived example 25 | when { 26 | allOf { 27 | branch pattern: 'production', comparator: 'EQUALS' 28 | branch pattern: /^release\/[A-Z].[A-Z].[A-Z]$/, comparator: 'REGEXP' 29 | branch pattern: 'main-**', comparator: 'GLOB' 30 | branch 'feature/*' 31 | } 32 | } 33 | steps { 34 | echo 'Executing allOf with branches' 35 | } 36 | } 37 | stage('Example allOf tags') { // Contrived example 38 | when { 39 | allOf { 40 | tag pattern: 'latest', comparator: 'EQUALS' 41 | tag pattern: /^release-[A-Z].[A-Z].[A-Z]$/, comparator: 'REGEXP' 42 | tag pattern: 'v-*', comparator: 'GLOB' 43 | tag 'version-*' 44 | } 45 | } 46 | steps { 47 | echo 'Executing allOf with tags' 48 | } 49 | } 50 | stage('Example allOf changeRequests') { 51 | when { 52 | allOf { 53 | changeRequest target: 'develop' 54 | changeRequest branch: 'feature/*', comparator:'GLOB' 55 | } 56 | } 57 | steps { 58 | echo 'Executing allOf with changeRequest' 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/AnyOf_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example anyOf expression') { 10 | when { 11 | anyOf { 12 | expression { 13 | return env.SHOULD_EXECUTE == 'true' 14 | } 15 | expression { 16 | return 1 == 2 17 | } 18 | } 19 | } 20 | steps { 21 | echo 'Executing anyOf with expression' 22 | } 23 | } 24 | stage('Example anyOf branches') { 25 | when { 26 | anyOf { 27 | branch pattern: 'production', comparator: 'EQUALS' 28 | branch pattern: /^release\/[A-Z].[A-Z].[A-Z]$/, comparator: 'REGEXP' 29 | branch pattern: 'main-**', comparator: 'GLOB' 30 | branch 'feature/*' 31 | } 32 | } 33 | steps { 34 | echo 'Executing anyOf with branch' 35 | } 36 | } 37 | stage('Example anyOf tags') { 38 | when { 39 | anyOf { 40 | tag pattern: 'latest', comparator: 'EQUALS' 41 | tag pattern: /^release-[A-Z].[A-Z].[A-Z]$/, comparator: 'REGEXP' 42 | tag pattern: 'v-*', comparator: 'GLOB' 43 | tag 'version-*' 44 | } 45 | } 46 | steps { 47 | echo 'Executing anyOf with tag' 48 | } 49 | } 50 | stage('Example anyOf changeRequests') { 51 | when { 52 | anyOf { 53 | changeRequest target: 'develop' 54 | changeRequest target: 'release/*', comparator: 'GLOB' 55 | } 56 | } 57 | steps { 58 | echo 'Executing anyOf with changeRequest' 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Branch_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example - EQUALS comparator') { 10 | when { 11 | branch pattern: 'develop', comparator: 'EQUALS' 12 | } 13 | steps { 14 | echo 'EQUALS (explicit)' 15 | } 16 | } 17 | stage('Example - GLOB comparator (implicit)') { 18 | when { 19 | branch 'feature/*' 20 | } 21 | steps { 22 | echo 'GLOB (implicit)' 23 | } 24 | } 25 | stage('Example - GLOB comparator (explicit)') { 26 | when { 27 | branch pattern: 'bugfix/*', comparator: 'GLOB' 28 | } 29 | steps { 30 | echo 'GLOB (explicit)' 31 | } 32 | } 33 | stage('Example - REGEXP comparator') { 34 | when { 35 | branch pattern: /^[a-z]*\/[a-z]*$/, comparator: 'REGEXP' 36 | } 37 | steps { 38 | echo 'REGEXP (explicit)' 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/BuildStatus_Failure_Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Failure') { 3 | error 'should fail' 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/BuildStatus_Success_Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Success') { 3 | echo 'should succeed' 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/ChangeRequest_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example test') { 10 | when { 11 | changeRequest() 12 | } 13 | steps { 14 | echo 'Test only change requests' 15 | } 16 | } 17 | stage('Example test target develop') { 18 | when { 19 | changeRequest target: 'develop' 20 | } 21 | steps { 22 | echo 'Test change requests with develop branch as target' 23 | } 24 | } 25 | stage('Example test branch feature') { 26 | when { 27 | changeRequest branch: 'feature/*', comparator: 'GLOB' 28 | } 29 | steps { 30 | echo 'Test change requests with any feature branch as source' 31 | } 32 | } 33 | stage('Example test author') { 34 | when { 35 | changeRequest author: 'unreliableUser', 36 | authorDisplayName: 'Unreliable User', 37 | authorEmail: 'unreliable.user@com.com' 38 | } 39 | steps { 40 | echo 'Test change requests with unreliableUser as author' 41 | } 42 | } 43 | stage('Example test id equals') { 44 | when { 45 | changeRequest id: '42', comparator: 'EQUALS' 46 | } 47 | steps { 48 | echo 'Test change request with id 42' 49 | } 50 | } 51 | stage('Example test title') { 52 | when { 53 | changeRequest title: '^[a-zA-Z0-9 -]+$', comparator: 'REGEXP' 54 | } 55 | steps { 56 | echo 'Test change requests with alphanumeric titles' 57 | } 58 | } 59 | stage('Example test url and fork') { 60 | when { 61 | changeRequest url: 'https://github.com*', fork: 'https://github.com*', comparator: 'GLOB' 62 | } 63 | steps { 64 | echo 'Test change requests with github in url and fork' 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/ComplexStages_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Example Build') { 5 | agent { docker 'maven:3-alpine' } 6 | stages { 7 | stage("Sub-Build Task 1") { 8 | steps { 9 | echo 'Hello, Maven' 10 | sh 'mvn --version' 11 | } 12 | } 13 | stage("Sub-Build Task 2") { 14 | steps { 15 | echo 'Go, Maven' 16 | sh 'mvn build' 17 | } 18 | } 19 | } 20 | } 21 | stage('Example Test') { 22 | agent { docker 'openjdk:8-jre' } 23 | steps { 24 | echo 'Hello, JDK' 25 | sh 'java -version' 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Credentials_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | environment { 4 | CC = 'clang' 5 | } 6 | stages { 7 | stage('Example') { 8 | environment { 9 | AN_ACCESS_KEY = credentials('my-prefined-secret-text') 10 | } 11 | steps { 12 | sh 'printenv' 13 | echo "${env}" 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Declarative_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | 3 | agent any 4 | 5 | environment { 6 | CC = 'gcc' 7 | } 8 | 9 | options { 10 | buildDiscarder(logRotator(numToKeepStr: '10')) 11 | skipStagesAfterUnstable() 12 | timestamps() 13 | } 14 | 15 | triggers { 16 | pollSCM('*/5 * * * *') 17 | } 18 | 19 | stages { 20 | 21 | stage('Checkout') { 22 | when { 23 | environment name: 'CC', value: 'clang' 24 | } 25 | steps { 26 | deleteDir() 27 | checkout scm 28 | } 29 | } 30 | 31 | stage('build') { 32 | agent { docker 'maven:3-alpine' } 33 | options { 34 | timeout(time: 20, unit: 'MINUTES') 35 | } 36 | steps { 37 | withEnv(["GRADLE_HOME=${tool name: 'GRADLE_3', type: 'hudson.plugins.gradle.GradleInstallation'}"]) { 38 | withEnv(["PATH=${env.PATH}:${env.GRADLE_HOME}/bin"]) { 39 | 40 | // Checking the env 41 | echo "GRADLE_HOME=${env.GRADLE_HOME}" 42 | echo "PATH=${env.PATH}" 43 | 44 | sh 'gradle clean build test -i' 45 | } 46 | } 47 | } 48 | } 49 | 50 | stage('validate') { 51 | steps { 52 | echo 'DONE: syntactic validation of Jenkinsfiles' 53 | } 54 | } 55 | } 56 | 57 | post { 58 | always { 59 | echo 'pipeline unit tests completed' 60 | } 61 | 62 | success { 63 | echo 'pipeline unit tests PASSED' 64 | } 65 | 66 | failure { 67 | echo 'pipeline unit tests FAILED' 68 | } 69 | 70 | aborted { 71 | echo 'pipeline unit tests ABORTED' 72 | } 73 | 74 | changed { 75 | echo 'pipeline unit tests results have CHANGED' 76 | } 77 | 78 | unstable { 79 | echo 'pipeline unit tests have gone UNSTABLE' 80 | } 81 | 82 | unsuccessful { 83 | echo 'pipeline unit tests UNSUCCESSFUL' 84 | } 85 | 86 | fixed { 87 | echo 'pipeline unit tests have been FIXED' 88 | } 89 | 90 | regression{ 91 | echo 'pipeline unit tests post REGRESSION' 92 | } 93 | 94 | cleanup { 95 | echo 'pipeline unit tests post CLEANUP' 96 | } 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Docker_Jenkinsfile: -------------------------------------------------------------------------------- 1 | 2 | def test_docker_build(testImageName) { 3 | stage('Test docker.build()') { 4 | def image = docker.build(testImageName) 5 | assert image.id == testImageName 6 | } 7 | } 8 | 9 | def test_docker_build_two_args(testImageName) { 10 | stage('Test docker.build() two args') { 11 | def image = docker.build(testImageName, '--build_arg arg1=val1 --build_arg arg2=val2' ) 12 | assert image.id == testImageName 13 | } 14 | } 15 | 16 | def test_docker_image(testImageName) { 17 | stage('Test docker.image()') { 18 | def image = docker.image(testImageName) 19 | assert image.id == testImageName 20 | } 21 | } 22 | 23 | def test_with_registry(testImageName) { 24 | stage('Test docker.withRegistry') { 25 | docker.withRegistry('test.registry', 'fake-credentials') { 26 | def image = docker.image(testImageName) 27 | echo "Hello from withRegistry ${image.id}" 28 | assert image.id == testImageName 29 | } 30 | } 31 | } 32 | 33 | def test_with_server(testImageName) { 34 | stage('Test docker.withServer()') { 35 | docker.withServer('test.server', 'fake-credentials') { 36 | def image = docker.image(testImageName) 37 | echo "Hello from withServer ${image.id}" 38 | assert image.id == testImageName 39 | } 40 | } 41 | } 42 | 43 | def test_with_tool(testImageName) { 44 | stage('Test docker.withTool()') { 45 | docker.withTool('test-docker') { 46 | def image = docker.image(testImageName) 47 | echo "Hello from withTool ${image.id}" 48 | assert image.id == testImageName 49 | } 50 | } 51 | } 52 | 53 | def test_image_name(testImageName) { 54 | stage('Test docker.image.imageName()') { 55 | def image = docker.image(testImageName) 56 | assert image.imageName() == testImageName 57 | } 58 | } 59 | 60 | def test_inside(testImageName) { 61 | stage('Test docker.image.inside()') { 62 | def image = docker.image(testImageName) 63 | image.inside { 64 | echo "Hello from inside ${image.id}" 65 | assert image.id == testImageName 66 | } 67 | } 68 | } 69 | 70 | def test_image_pull(testImageName) { 71 | stage('Test docker.image.pull()') { 72 | docker.image(testImageName).pull() 73 | } 74 | } 75 | 76 | def test_image_push(testImageName) { 77 | stage('Test docker.image.push()') { 78 | def image = docker.image(testImageName) 79 | image.push('test-tag') 80 | assert image.tagname == 'test-tag' 81 | } 82 | } 83 | 84 | def test_image_run(testImageName){ 85 | stage('Test docker.image.run()') { 86 | def container = docker.image(testImageName).run() 87 | container.stop() 88 | } 89 | } 90 | 91 | def test_image_tag(testImageName) { 92 | stage('Test docker.image.tag()') { 93 | def image = docker.image(testImageName) 94 | image.tag('test') 95 | assert image.tagname == 'test' 96 | } 97 | } 98 | 99 | def test_image_with_run(testImageName) { 100 | stage('Test docker.image.withRun()') { 101 | def image = docker.image(testImageName) 102 | image.withRun { 103 | echo "Hello from withRun ${image.id}" 104 | assert image.id == testImageName 105 | } 106 | } 107 | } 108 | 109 | return this 110 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Docker_agentInStep_JenkinsFile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | 3 | stages { 4 | stage('Maven Build') { 5 | agent { 6 | docker { 7 | image 'maven' 8 | label 'latest' 9 | alwaysPull true 10 | } 11 | } 12 | steps { 13 | sh 'mvn install' 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Dockerfile_Agent_Default_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | stages { 3 | stage('Build') { 4 | agent { 5 | dockerfile true 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Dockerfile_Agent_Only_Filename_JenkinsFile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | stages { 3 | stage('Build') { 4 | agent { 5 | dockerfile { 6 | filename 'Dockerfile' 7 | } 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Dockerfile_agent_JenkinsFile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | stages { 3 | stage('Build') { 4 | agent { 5 | dockerfile { 6 | filename 'Dockerfile' 7 | label 'linux' 8 | registryUrl 'https://registry.example.com' 9 | registryCredentialsId 'MY_CREDENTIALS_ID' 10 | args '-v /tmp:/ws' 11 | additionalBuildArgs '--pull' 12 | } 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Environment_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | environment { 4 | LEVAR1 = "LE VALUE 1" 5 | } 6 | stages { 7 | stage('Example') { 8 | environment { 9 | LEVAR1 = "LE NEW VALUE" 10 | LEVAR2 = "A COPY OF ${env.LEVAR1} in build#${currentBuild.number}" 11 | } 12 | steps { 13 | echo "LEVAR1 ${env.LEVAR1}" 14 | echo "LEVAR2 ${env.LEVAR2}" 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Kubernetes_Agent_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Example Build') { 5 | agent { 6 | kubernetes { 7 | cloud 'kubernetes' 8 | label 'testLabel' 9 | yaml """metadata: 10 | namespace: "jenkins" 11 | spec: 12 | containers: 13 | - name: jnlp 14 | image: jenkins/slave:4.3-8 15 | resources: 16 | requests: 17 | cpu: "500m" 18 | memory: "4Gi" 19 | limits: 20 | memory: "4Gi" 21 | cpu: 2.0 22 | workingDir: /home/jenkins/agent 23 | env: 24 | - name: CONTAINER_ENV_VAR 25 | value: jnlp 26 | - name: JAVA_OPTS 27 | value: "-Duser.timezone=Europe/Amsterdam" 28 | volumeMounts: 29 | - name: log4j2-jenkins 30 | mountPath: "/usr/local/etc/jenkins/log4j2.xml" 31 | subPath: log4j2.xml 32 | volumes: 33 | - name: log4j2-jenkins 34 | configMap: 35 | name: log4j2-jenkins 36 | """ 37 | } 38 | } 39 | steps { 40 | echo 'Hello, Kubernetes' 41 | container("maven"){ 42 | sh 'mvn --version' 43 | } 44 | } 45 | } 46 | stage('Example Test') { 47 | agent { kubernetes { 48 | cloud 'kubernetes' 49 | label 'testLabel' 50 | yamlFile 'KubernetesPod.yaml' 51 | } 52 | } 53 | steps { 54 | echo 'Hello, JDK' 55 | sh 'java -version' 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Kubernetes_Default_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { kubernetes true } 3 | stages { 4 | stage('Example Test') { 5 | steps { 6 | echo 'Hello, JDK' 7 | sh 'java -version' 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Kubernetes_Map_Agent_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Example Build') { 5 | agent { 6 | kubernetes( 7 | [ 'cloud': 'kubernetes', 8 | 'label': 'testLabel', 9 | 'yaml': """metadata: 10 | namespace: "jenkins" 11 | spec: 12 | containers: 13 | - name: jnlp 14 | image: jenkins/slave:4.3-8 15 | resources: 16 | requests: 17 | cpu: "500m" 18 | memory: "4Gi" 19 | limits: 20 | memory: "4Gi" 21 | cpu: 2.0 22 | workingDir: /home/jenkins/agent 23 | env: 24 | - name: CONTAINER_ENV_VAR 25 | value: jnlp 26 | - name: JAVA_OPTS 27 | value: "-Duser.timezone=Europe/Amsterdam" 28 | volumeMounts: 29 | - name: log4j2-jenkins 30 | mountPath: "/usr/local/etc/jenkins/log4j2.xml" 31 | subPath: log4j2.xml 32 | volumes: 33 | - name: log4j2-jenkins 34 | configMap: 35 | name: log4j2-jenkins 36 | """] 37 | ) 38 | } 39 | steps { 40 | echo 'Hello, Kubernetes' 41 | sh 'mvn --version' 42 | } 43 | } 44 | stage('Example Test') { 45 | agent { kubernetes { 46 | cloud 'kubernetes' 47 | label 'testLabel' 48 | yamlFile 'KubernetesPod.yaml' 49 | } 50 | } 51 | steps { 52 | echo 'Hello, JDK' 53 | sh 'java -version' 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Mock_existing_function_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { node { label 'test1' } } 3 | stages { 4 | stage('sdfsdf') { 5 | steps { 6 | githubNotify status: 'PENDING', context: 'Pipeline' 7 | runFunc() 8 | } 9 | } 10 | } 11 | } 12 | 13 | def runFunc(){ 14 | echo "inside runFunc" 15 | doSomeStuff() 16 | } 17 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Mock_existing_function_Jenkinsfile_params: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { node { label 'test1' } } 3 | stages { 4 | stage('sdfsdf') { 5 | steps { 6 | githubNotify status: 'PENDING', context: 'Pipeline' 7 | runFuncWithParam("one") 8 | } 9 | } 10 | } 11 | } 12 | 13 | def runFuncWithParam(String oneString) { 14 | echo "inside runFuncWithParam" 15 | doSomeStuffWithParam() 16 | } 17 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Nested_AllOf_And_AnyOf_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example nested when allOf anyOf expression') { 10 | when { 11 | allOf { 12 | anyOf { 13 | expression { 14 | return env.OPTIONAL_1 == 'true' 15 | } 16 | expression { 17 | return env.OPTIONAL_2 == 'true' 18 | } 19 | } 20 | anyOf { 21 | expression { 22 | return env.OPTIONAL_3 == 'true' 23 | } 24 | expression { 25 | return env.OPTIONAL_4 == 'true' 26 | } 27 | } 28 | } 29 | } 30 | steps { 31 | echo 'Executing nested when allOf anyOf expression' 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Nested_AnyOf_And_AllOf_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example nested when anyOf allOf expression') { 10 | when { 11 | anyOf { 12 | allOf { 13 | expression { 14 | return env.OPTIONAL_1 == 'true' 15 | } 16 | expression { 17 | return env.OPTIONAL_2 == 'true' 18 | } 19 | } 20 | expression { 21 | return env.OPTIONAL_3 == 'true' 22 | } 23 | } 24 | } 25 | steps { 26 | echo 'Executing nested when anyOf allOf expression' 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Nested_BeforeAgent_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example nested when beforeAgent expression') { 10 | agent { 11 | label "beforeAgent-testLabel" 12 | } 13 | when { 14 | beforeAgent true 15 | branch 'main' 16 | } 17 | steps { 18 | echo 'Executing nested when beforeAgent expression' 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Non_Valid_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Example Build') { 5 | agent { docker 'maven:3-alpine' } 6 | steps { 7 | echo 'Hello, Maven' 8 | sh 'mvn --version' 9 | } 10 | } 11 | stage('Example Test') { 12 | agent { docker 'openjdk:8-jre' } 13 | steps { 14 | echo "$someInvalidVar" 15 | echo 'Hello, JDK' 16 | sh 'java -version' 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Parallel_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Run Tests') { 5 | failFast true 6 | parallel { 7 | stage('Test On Windows') { 8 | agent { 9 | label "windows" 10 | } 11 | steps { 12 | sh "run-tests.exe" 13 | } 14 | } 15 | stage('Test On Linux') { 16 | agent { 17 | label "linux" 18 | } 19 | steps { 20 | sh "run-tests.sh" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Parallel_NestedStages_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | stages { 3 | stage('Parallel Stage') { 4 | parallel { 5 | stage('Branch A') { 6 | stages { 7 | stage('Nested 1') { 8 | steps { 9 | echo "In stage Nested 1 within Branch A" 10 | } 11 | } 12 | } 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Parallel_When_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('Analysis') { 5 | when { environment name: 'SKIP_CI', value: 'false' } 6 | parallel { 7 | stage('Lint') { 8 | steps { 9 | sh 'run-lint.sh' 10 | } 11 | } 12 | stage('Test') { 13 | steps { 14 | sh 'run-tests.sh' 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Params_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | parameters { 4 | string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') 5 | } 6 | stages { 7 | stage('Example') { 8 | steps { 9 | echo "Hello ${params.PERSON}" 10 | } 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/StageAndSteps_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('B') { 5 | agent {label 'labelB'} 6 | post { always {echo 'post B'}} 7 | steps { echo 'B' } 8 | stages { 9 | stage('C') { 10 | agent {label 'labelC'} 11 | post { always {echo 'post C'}} 12 | steps { 13 | echo 'C' 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/StageFailed_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | stages { 3 | stage('Failed Stage') { 4 | steps { 5 | currentBuild.result = 'FAILURE' 6 | } 7 | } 8 | stage('Not executed stage') { 9 | steps { 10 | echo 'I will not be executed!' 11 | } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/Tag_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example Build') { 5 | steps { 6 | echo 'Hello World' 7 | } 8 | } 9 | stage('Example - EQUALS comparator') { 10 | when { 11 | tag pattern: 'x.y.z', comparator: 'EQUALS' 12 | } 13 | steps { 14 | echo 'EQUALS (explicit)' 15 | } 16 | } 17 | stage('Example - GLOB comparator (implicit)') { 18 | when { 19 | tag 'v*' 20 | } 21 | steps { 22 | echo 'GLOB (implicit)' 23 | } 24 | } 25 | stage('Example - GLOB comparator (explicit)') { 26 | when { 27 | tag pattern: 'v-*', comparator: 'GLOB' 28 | } 29 | steps { 30 | echo 'GLOB (explicit)' 31 | } 32 | } 33 | stage('Example - REGEXP comparator') { 34 | when { 35 | tag pattern: /^[0-9].[0-9].[0-9]$/, comparator: 'REGEXP' 36 | } 37 | steps { 38 | echo 'REGEXP (explicit)' 39 | } 40 | } 41 | stage('Example Release Notes') { 42 | when { 43 | buildingTag() 44 | } 45 | steps { 46 | echo 'Generating Release Notes for any tag' 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/ThisScope_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('issue#419') { 5 | steps { 6 | script { 7 | new Messages(this).add("text") 8 | } 9 | } 10 | } 11 | } 12 | } 13 | 14 | class Messages implements Serializable { 15 | def steps 16 | 17 | Messages(steps) { 18 | this.steps = steps 19 | } 20 | 21 | def add(String message) { 22 | this.steps.writeFile(file: "messages/messages.msg", text: message) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/WithEnvEquals_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('withenvequals') { 5 | steps { 6 | withEnv(["SOMEVAR=SOMETHING=SOME_OTHER_VAR"]) { 7 | echo "SOMEVAR inside closure = ${env.SOMEVAR}" 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/WithEnv_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('withenvbug') { 5 | steps { 6 | withEnv(["SOMEVAR=SOMEVAL"]) { 7 | echo "SOMEVAR inside closure = ${env.SOMEVAR}" 8 | withEnv(["SOMEVAR=SOMEVAL"]) { 9 | echo "SOMEVAR overlapping inside closure = ${env.SOMEVAR}" 10 | } 11 | echo "SOMEVAR restored inside closure = ${env.SOMEVAR}" 12 | } 13 | //SOMEVAR should be null after closure 14 | echo "SOMEVAR outside closure = ${env.SOMEVAR}" 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/not_Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('Example not') { 5 | when { 6 | not { 7 | branch "master" 8 | } 9 | } 10 | steps { 11 | echo 'Running' 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/jenkins/jenkinsfiles/withCredentials_Jenkinsfile: -------------------------------------------------------------------------------- 1 | 2 | pipeline { 3 | agent any 4 | stages { 5 | stage("run") { 6 | withCredentials([ 7 | usernamePassword( credentialsId: 'my_cred_id', usernameVariable: 'user', passwordVariable: 'pass' ), 8 | string( credentialsId: 'docker_cred', variable: 'docker_pass' ), 9 | string( credentialsId: 'ssh_cred', variable: 'ssh_pass' ) 10 | ]) { 11 | // Ensure values are set on entry 12 | echo "User/Pass = $user/$pass" 13 | echo "Docker = $docker_pass" 14 | echo "SSH = $ssh_pass" 15 | 16 | withCredentials([ 17 | usernamePassword( credentialsId: 'my_cred_id', usernameVariable: 'user', passwordVariable: 'pass' ), 18 | string( credentialsId: 'docker_cred', variable: 'docker_pass' ), 19 | string( credentialsId: 'ssh_cred', variable: 'ssh_pass' ) 20 | ]) { 21 | // Ensure nested values are in place 22 | echo "Nested User/Pass = $user/$pass" 23 | echo "Nested Docker = $docker_pass" 24 | echo "Nested SSH = $ssh_pass" 25 | } 26 | 27 | // Ensure original values are restored 28 | echo "Restored User/Pass = $user/$pass" 29 | echo "Restored Docker = $docker_pass" 30 | echo "Restored SSH = $ssh_pass" 31 | } 32 | 33 | // Ensure original state where the values are not set 34 | echo "Cleared User/Pass = $user/$pass" 35 | echo "Cleared Docker = $docker_pass" 36 | echo "Cleared SSH = $ssh_pass" 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/test/jenkins/job/callStackDump.jenkins: -------------------------------------------------------------------------------- 1 | 2 | def someMethod1() { 3 | 'method1' 4 | } 5 | 6 | def someMethod2() { 7 | 'method2' 8 | } 9 | -------------------------------------------------------------------------------- /src/test/jenkins/job/customMethod.jenkins: -------------------------------------------------------------------------------- 1 | node() { 2 | customMethod() 3 | } 4 | 5 | def customMethod() { 6 | echo 'executing custom method closure' 7 | } 8 | -------------------------------------------------------------------------------- /src/test/jenkins/job/customMethodWithArguments.jenkins: -------------------------------------------------------------------------------- 1 | node() { 2 | customMethodWithArguments('stringArg', 42, ['collectionArg', 42]) 3 | } 4 | 5 | def customMethodWithArguments(String arg1, int arg2, Collection arg3) { 6 | echo "executing custom method with arguments closure (arguments: '${arg1}', '${arg2}', '${arg3}')" as String 7 | } -------------------------------------------------------------------------------- /src/test/jenkins/job/exampleJob.jenkins: -------------------------------------------------------------------------------- 1 | def execute() { 2 | node() { 3 | def utils = load "src/test/jenkins/lib/utils.jenkins" 4 | def properties = load 'src/test/jenkins/lib/properties.jenkins' 5 | 6 | String revision = stage('Checkout') { 7 | checkout scm 8 | return utils.currentRevision() 9 | } 10 | gitlabBuilds(builds: ["build", "test"]) { 11 | stage("build") { 12 | gitlabCommitStatus("build") { 13 | sleep 20 14 | sh "mvn clean package -DskipTests -DgitRevision=$revision" 15 | } 16 | } 17 | 18 | stage("test") { 19 | gitlabCommitStatus("test") { 20 | println properties.key 21 | sh "mvn verify -DgitRevision=$revision" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | sleep 20 29 | 30 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/globalVar.jenkins: -------------------------------------------------------------------------------- 1 | #!groovy 2 | 3 | Properties p = new Properties() 4 | 5 | node() { 6 | 7 | stage('One') { 8 | 9 | echo "Stage One" 10 | 11 | p.setProperty('PROP_1', 'VAL_1') 12 | 13 | doWithProperties(new TreeMap(p)) 14 | } 15 | 16 | stage('Two') { 17 | 18 | echo "Stage Two" 19 | 20 | p.setProperty('PROP_2', 'VAL_2') 21 | 22 | doWithProperties(new TreeMap(p)) 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/test/jenkins/job/immutableMapArgs.jenkins: -------------------------------------------------------------------------------- 1 | //Assume these were generated by some helper method that wants to protect the 2 | //arguments it generates from mutation. 3 | pretendArgsFromFarUpstream = [ 4 | file: "foo.txt", 5 | text: "All bar, all the time", 6 | ].asImmutable() 7 | 8 | node() { 9 | writeFile(pretendArgsFromFarUpstream) 10 | } 11 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class/test_annotation.jenkins: -------------------------------------------------------------------------------- 1 | @Library("test_cross_class_tres") _ 2 | 3 | def objectAB = new org.test.ClassAB() 4 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class/test_dynamic.jenkins: -------------------------------------------------------------------------------- 1 | def lib = library("test_cross_class_dos@beta") 2 | 3 | def objectAB = lib.org.test.ClassAB.new() 4 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class/test_implicit.jenkins: -------------------------------------------------------------------------------- 1 | 2 | def objectAB = new org.test.ClassAB() 3 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_lazy_load/test_var_with_lib_class_arg.jenkins: -------------------------------------------------------------------------------- 1 | @Library("test_cross_class_as_var_arg_2") 2 | import org.test.extra.Monster2 3 | @Library("test_cross_class_as_var_arg_1") 4 | import org.test.Monster1 5 | 6 | vampire = new Monster1("Dracula") 7 | monster1(vampire) -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_pre_loaded/test_annotation.jenkins: -------------------------------------------------------------------------------- 1 | @Library("test_pre_loaded_cross_class_tres")_ 2 | 3 | new org.test.ClassA() 4 | new org.test.ClassB() 5 | 6 | def objectAB = new org.test.ClassAB() 7 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_pre_loaded/test_dynamic.jenkins: -------------------------------------------------------------------------------- 1 | def lib = library("test_pre_loaded_cross_class_dos@beta") 2 | 3 | lib.org.test.ClassA.new() 4 | lib.org.test.ClassB.new() 5 | 6 | def objectAB = lib.org.test.ClassAB.new() 7 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_pre_loaded/test_implicit.jenkins: -------------------------------------------------------------------------------- 1 | 2 | new org.test.ClassA() 3 | new org.test.ClassB() 4 | 5 | def objectAB = new org.test.ClassAB() 6 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_with_pipeline_ref/test_annotation.jenkins: -------------------------------------------------------------------------------- 1 | @Library("test_cross_class_with_pipeline_ref_tres") _ 2 | 3 | def objectAB = new org.test.ClassAB(this) 4 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_with_pipeline_ref/test_dynamic.jenkins: -------------------------------------------------------------------------------- 1 | def lib = library("test_cross_class_with_pipeline_ref_dos") 2 | 3 | def objectAB = lib.org.test.ClassAB.new(this) 4 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_class_with_pipeline_ref/test_implicit.jenkins: -------------------------------------------------------------------------------- 1 | 2 | def objectAB = new org.test.ClassAB(this) 3 | objectAB.methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_library/test_cross_class_annotation.jenkins: -------------------------------------------------------------------------------- 1 | @Library("libA") _ 2 | @Library("libB") _ 3 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_library/test_cross_class_dynamic.jenkins: -------------------------------------------------------------------------------- 1 | def lib = library("test_cross_vars_dos@beta") 2 | 3 | methodA() 4 | methodB() 5 | methodAB() 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_library/test_cross_class_implicit.jenkins: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/JenkinsPipelineUnit/18fbbb546c3dba7faf1da9f1bbfe159ba7e599c1/src/test/jenkins/job/library/cross_library/test_cross_class_implicit.jenkins -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_vars/test_annotation.jenkins: -------------------------------------------------------------------------------- 1 | @Library("test_cross_vars_tres@gamma") _ 2 | methodB() 3 | methodAB() 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_vars/test_dynamic.jenkins: -------------------------------------------------------------------------------- 1 | def lib = library("test_cross_vars_dos@beta") 2 | 3 | methodA() 4 | methodB() 5 | methodAB() 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/cross_vars/test_implicit.jenkins: -------------------------------------------------------------------------------- 1 | methodA() 2 | methodB() 3 | methodAB() -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob.jenkins: -------------------------------------------------------------------------------- 1 | package job.library 2 | 3 | @Library('commons') 4 | import net.courtanet.jenkins.Utils 5 | 6 | sh acme.name 7 | acme.name = 'something' 8 | sh acme.name 9 | 10 | acme.caution('world') 11 | sayHello 'World' 12 | sayHello() 13 | 14 | def execute() { 15 | parallel( 16 | action1: { 17 | node() { 18 | sayHello('arg1', 'arg2') 19 | sayHello(Arrays.asList('1','2').toArray(new String[0])) 20 | def utils = new Utils() 21 | sh "${utils.gitTools()}" 22 | sh 'sleep 3' 23 | String pom = libraryResource 'net/courtanet/jenkins/pom.xml' 24 | println pom 25 | } 26 | }, 27 | action2: { 28 | node() { 29 | sh 'sleep 4' 30 | error 'message' 31 | } 32 | } 33 | ) 34 | } 35 | 36 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob_dynamic_map.jenkins: -------------------------------------------------------------------------------- 1 | def execute() { 2 | node() { 3 | def lib = library(identifier: 'commons', changelog: false) 4 | def utils = lib.net.courtanet.jenkins.Utils.new() 5 | sh "${utils.gitTools()}" 6 | } 7 | } 8 | 9 | return this 10 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob_feature.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature') _ 2 | 3 | greetings {} 4 | 5 | def execute() { 6 | parallel( 7 | action1: { 8 | node() { 9 | def utils = new net.courtanet.jenkins.Utils2() 10 | def s = net.courtanet.jenkins.Utils2.tools() 11 | println s 12 | helloMessage { 13 | message = "hello this is a test" 14 | } 15 | sh "${utils.gitTools()}" 16 | sh 'sleep 3' 17 | } 18 | }, 19 | action2: { 20 | node() { 21 | sh 'sleep 4' 22 | error 'message' 23 | } 24 | } 25 | ) 26 | } 27 | 28 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob_feature2.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature2') 2 | import net.courtanet.jenkins.Utils 3 | 4 | def execute() { 5 | parallel( 6 | action1: { 7 | node() { 8 | def utils = new Utils() 9 | sh "${utils.gitTools()}" 10 | sh 'sleep 3' 11 | } 12 | }, 13 | action2: { 14 | node() { 15 | sh 'sleep 4' 16 | error 'message' 17 | } 18 | } 19 | ) 20 | } 21 | 22 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob_implicit.jenkins: -------------------------------------------------------------------------------- 1 | import net.courtanet.jenkins.Utils 2 | 3 | def execute() { 4 | parallel( 5 | action1: { 6 | node() { 7 | def utils = new Utils() 8 | sh "${utils.gitTools()}" 9 | sh 'sleep 3' 10 | } 11 | }, 12 | action2: { 13 | node() { 14 | sayHello() 15 | sh 'sleep 4' 16 | error 'message' 17 | } 18 | } 19 | ) 20 | } 21 | 22 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob_inline_library.jenkins: -------------------------------------------------------------------------------- 1 | package job.library 2 | 3 | def lib = library('commons') 4 | 5 | sh acme.name 6 | acme.name = 'something' 7 | sh acme.name 8 | 9 | acme.caution('world') 10 | sayHello 'World' 11 | sayHello() 12 | 13 | def execute() { 14 | parallel( 15 | action1: { 16 | node() { 17 | def utils = lib.net.courtanet.jenkins.Utils.new() 18 | sh "${utils.gitTools()}" 19 | sh 'sleep 3' 20 | } 21 | }, 22 | action2: { 23 | node() { 24 | sayHello() 25 | sh 'sleep 4' 26 | error 'message' 27 | } 28 | } 29 | ) 30 | } 31 | 32 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/library/libraryJob_master.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@master') 2 | import net.courtanet.jenkins.Utils 3 | 4 | def execute() { 5 | parallel( 6 | action1: { 7 | node() { 8 | def utils = new Utils() 9 | sh "${utils.gitTools()}" 10 | sh 'sleep 3' 11 | } 12 | }, 13 | action2: { 14 | node() { 15 | sh 'sleep 4' 16 | error 'message' 17 | } 18 | } 19 | ) 20 | } 21 | 22 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/library/params_not_accessible.jenkins: -------------------------------------------------------------------------------- 1 | @Library('params_not_accessible') 2 | import org.test.LibClass 3 | 4 | pipeline { 5 | stages { 6 | stage('Test stage'){ 7 | steps { 8 | out = new LibClass().getX() 9 | testVar = 'changedValue' 10 | echo "Printing ${out}" 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_lib_call_shell_annotation.jenkins: -------------------------------------------------------------------------------- 1 | @Library("test_lib_call_shell_dos@beta") import org.test.LaClass 2 | def lacls = new LaClass() 3 | lacls.callJenkinsSH("ls -la") 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_lib_call_shell_dynamic.jenkins: -------------------------------------------------------------------------------- 1 | def lib = library("test_lib_call_shell_uno@alpha") 2 | def lacls = lib.org.test.LaClass.new() 3 | lacls.callJenkinsSH("ls -la") 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_lib_call_with_null.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature') _ 2 | 3 | // Test calling a one argument global with null 4 | oneArg('Not null') 5 | oneArg(null) 6 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_lib_var_not_defined_in_env.jenkins: -------------------------------------------------------------------------------- 1 | @Library("env_var_not_defined") _ 2 | 3 | pipeline { 4 | 5 | environment { 6 | prop1 = envHelper.property1() 7 | } 8 | 9 | stages { 10 | stage('Test stage'){ 11 | steps { 12 | echo "prop1=${env.prop1}" 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_libraryResource_as_base64.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature') _ 2 | 3 | // Test retrieving a library resource with default encoding 4 | echo libraryResource(resource: 'net/courtanet/jenkins/icon.png', encoding: 'Base64') 5 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_libraryResource_with_encoding.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature') _ 2 | 3 | // Test retrieving a library resource with default encoding 4 | echo libraryResource(resource: 'net/courtanet/jenkins/plaintext.iso-8859-1.txt', encoding: 'ISO-8859-15') 5 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_libraryResource_with_string.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature') _ 2 | 3 | // Test retrieving a library resource with default encoding 4 | echo libraryResource('net/courtanet/jenkins/plaintext.utf8.txt') 5 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_libraryResource_without_encoding.jenkins: -------------------------------------------------------------------------------- 1 | @Library('commons@feature') _ 2 | 3 | // Test retrieving a library resource with default encoding 4 | echo libraryResource(resource: 'net/courtanet/jenkins/plaintext.utf8.txt') 5 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_params_immutable_declarative.jenkins: -------------------------------------------------------------------------------- 1 | pipeline { 2 | parameters { 3 | string( 4 | name: 'TEST_STRING', 5 | defaultValue: 'original' 6 | ) 7 | } 8 | 9 | stages { 10 | stage('Test declarative parameters') { 11 | steps { 12 | script { 13 | params.TEST_STRING = 'new' 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/jenkins/job/library/test_params_not_defined_in_env.jenkins: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | parameters { 4 | string name: 'VERSION', defaultValue: 'default-version' 5 | } 6 | environment { 7 | VERSION = "${params.VERSION}" 8 | } 9 | stages { 10 | stage('Print VERSION') { 11 | steps { 12 | echo env.VERSION // null when VERSION = "${VERSION}" 13 | echo VERSION // default-version when VERSION = "${VERSION}" 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/jenkins/job/parallelJob.jenkins: -------------------------------------------------------------------------------- 1 | def execute() { 2 | s = [s1:[name:"action1-name", body:{ 3 | node() { 4 | sh 'sleep 3' 5 | error 'message' 6 | } 7 | }], s2:[name: "action2-name", body:{ 8 | node() { 9 | sh 'sleep 4' 10 | } 11 | }]] 12 | 13 | parallel( 14 | "$s.s1.name":s.s1.body, 15 | "$s.s2.name":s.s2.body, 16 | failFast:true 17 | ) 18 | } 19 | 20 | return this 21 | -------------------------------------------------------------------------------- /src/test/jenkins/job/parameters.jenkins: -------------------------------------------------------------------------------- 1 | properties([ 2 | parameters([ 3 | booleanParam(name: 'myBooleanParam', description: 'My boolean typed parameter'), 4 | string(name: 'myStringParam', defaultValue: 'my default value', description: 'My string typed parameter') 5 | ]) 6 | ]) 7 | 8 | echo("'myStringParam' value is default: ${params.myStringParam}") 9 | -------------------------------------------------------------------------------- /src/test/jenkins/job/serialize.jenkins: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonSlurper 2 | 3 | def execute() { 4 | node() { 5 | def utils = load "src/test/jenkins/lib/utils.jenkins" 6 | stage('Checkout') { 7 | checkout scm 8 | gitlabBuilds(builds: ["build", "test"]) { 9 | stage("build") { 10 | def method = myMethod(null) 11 | echo method 12 | gitlabCommitStatus("build") { 13 | def result = parseJson(""" 14 | [{ 15 | "name": "AMX-12345_test", 16 | "commit": { 17 | "id": "08a3fb68fc60b59ed4c585a847c88bbe22597b10", 18 | "parent_ids": [ 19 | { "key": "value"} 20 | ], 21 | "test": null, 22 | "authored_date": "2017-01-18T14:09:58.000+01:00", 23 | "author_name": "bob", 24 | "author_email": "bob@lesfurets.com", 25 | "committed_date": "2017-01-18T14:09:58.000+01:00", 26 | "committer_name": "bob", 27 | "committer_email": "bob@lesfurets.com" 28 | }, 29 | "merged": false, 30 | "protected": false, 31 | "developers_can_push": false, 32 | "developers_can_merge": false 33 | }]""") 34 | def res = result[0] 35 | sh "mvn clean package -DskipTests ${res.commit.id}" 36 | } 37 | } 38 | 39 | stage("test") { 40 | gitlabCommitStatus("test") { 41 | sh 'mvn verify' 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | @NonCPS 50 | def parseJson(String jsonText) { 51 | return new JsonSlurper().parseText(jsonText) 52 | } 53 | 54 | @NonCPS 55 | Map deepCloneMap(Map lazyMap) { 56 | Map result = [:] 57 | for (String key : lazyMap.keySet()){ 58 | result.put(key, deepClone(lazyMap[key])) 59 | } 60 | return result 61 | } 62 | 63 | // A collection may contain lazy map 64 | @NonCPS 65 | Collection deepCloneCollection(Collection collection) { 66 | Collection result = [] 67 | for (Object o : collection) { 68 | result.add(deepClone(o)) 69 | } 70 | return result 71 | } 72 | 73 | @NonCPS 74 | def deepClone(def mapOrCollection) { 75 | if (mapOrCollection instanceof Map) { 76 | return deepCloneMap(mapOrCollection) 77 | } else if (mapOrCollection instanceof Collection) { 78 | return deepCloneCollection(mapOrCollection) 79 | } else { 80 | return mapOrCollection 81 | } 82 | } 83 | 84 | def myMethod(String foo) { 85 | return 'bar' 86 | } 87 | 88 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/serializeCPS.jenkins: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonSlurper 2 | 3 | def execute() { 4 | node() { 5 | def utils = load "src/test/jenkins/lib/utils.jenkins" 6 | stage('Checkout') { 7 | checkout scm 8 | gitlabBuilds(builds: ["build", "test"]) { 9 | stage("build") { 10 | def method = myMethod null 11 | echo method 12 | gitlabCommitStatus("build") { 13 | def result = parseJson(""" 14 | [{ 15 | "name": "AMX-12345_test", 16 | "commit": { 17 | "id": "08a3fb68fc60b59ed4c585a847c88bbe22597b10", 18 | "parent_ids": [ 19 | { "key": "value"} 20 | ], 21 | "test": null, 22 | "authored_date": "2017-01-18T14:09:58.000+01:00", 23 | "author_name": "bob", 24 | "author_email": "bob@lesfurets.com", 25 | "committed_date": "2017-01-18T14:09:58.000+01:00", 26 | "committer_name": "bob", 27 | "committer_email": "bob@lesfurets.com" 28 | }, 29 | "merged": false, 30 | "protected": false, 31 | "developers_can_push": false, 32 | "developers_can_merge": false 33 | }]""") 34 | def res = result[0] 35 | sh "mvn clean package -DskipTests ${res.commit.id}" 36 | } 37 | } 38 | 39 | stage("test") { 40 | gitlabCommitStatus("test") { 41 | sh 'mvn verify' 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | @NonCPS 50 | def parseJson(String jsonText) { 51 | return deepClone(new JsonSlurper().parseText(jsonText)) 52 | } 53 | 54 | @NonCPS 55 | Map deepCloneMap(Map lazyMap) { 56 | Map result = [:] 57 | for (String key : lazyMap.keySet()){ 58 | result.put(key, deepClone(lazyMap[key])) 59 | } 60 | return result 61 | } 62 | 63 | // A collection may contain lazy map 64 | @NonCPS 65 | Collection deepCloneCollection(Collection collection) { 66 | Collection result = [] 67 | for (Object o : collection) { 68 | result.add(deepClone(o)) 69 | } 70 | return result 71 | } 72 | 73 | @NonCPS 74 | def deepClone(def mapOrCollection) { 75 | if (mapOrCollection instanceof Map) { 76 | return deepCloneMap(mapOrCollection) 77 | } else if (mapOrCollection instanceof Collection) { 78 | return deepCloneCollection(mapOrCollection) 79 | } else { 80 | return mapOrCollection 81 | } 82 | } 83 | 84 | def myMethod(String foo) { 85 | return 'bar' 86 | } 87 | 88 | 89 | return this -------------------------------------------------------------------------------- /src/test/jenkins/job/shouldFail/forEach.jenkins: -------------------------------------------------------------------------------- 1 | node() { 2 | stage('List') { 3 | hello() 4 | } 5 | } 6 | 7 | void hello() { 8 | [1, 2, 3].each{ println it } 9 | } -------------------------------------------------------------------------------- /src/test/jenkins/job/shouldFail/nonCpsCallingCps.jenkins: -------------------------------------------------------------------------------- 1 | node() { 2 | stage('List') { 3 | List list = createList() 4 | } 5 | } 6 | 7 | long getLong() { 8 | return 2L 9 | } 10 | 11 | @NonCPS 12 | List createList() { 13 | getLong() 14 | return [] 15 | } -------------------------------------------------------------------------------- /src/test/jenkins/job/verify.jenkins: -------------------------------------------------------------------------------- 1 | def someStringMethod(String someString1, String someString2="") { 2 | return someString1 + someString2 3 | } 4 | 5 | def voidMethod() { 6 | echo "some output" 7 | } 8 | -------------------------------------------------------------------------------- /src/test/jenkins/job/withCredentials.jenkins: -------------------------------------------------------------------------------- 1 | node { 2 | withCredentials([ 3 | usernamePassword( credentialsId: 'my_cred_id', usernameVariable: 'user', passwordVariable: 'pass' ), 4 | string( credentialsId: 'docker_cred', variable: 'docker_pass' ), 5 | string( credentialsId: 'ssh_cred', variable: 'ssh_pass' ) 6 | ]) { 7 | // Ensure values are set on entry 8 | echo "User/Pass = $user/$pass" 9 | echo "Docker = $docker_pass" 10 | echo "SSH = $ssh_pass" 11 | 12 | withCredentials([ 13 | usernamePassword( credentialsId: 'my_cred_id', usernameVariable: 'user', passwordVariable: 'pass' ), 14 | string( credentialsId: 'docker_cred', variable: 'docker_pass' ), 15 | string( credentialsId: 'ssh_cred', variable: 'ssh_pass' ) 16 | ]) { 17 | // Ensure nested values are in place 18 | echo "Nested User/Pass = $user/$pass" 19 | echo "Nested Docker = $docker_pass" 20 | echo "Nested SSH = $ssh_pass" 21 | } 22 | 23 | // Ensure original values are restored 24 | echo "Restored User/Pass = $user/$pass" 25 | echo "Restored Docker = $docker_pass" 26 | echo "Restored SSH = $ssh_pass" 27 | } 28 | 29 | // Ensure original state where the values are not set 30 | echo "Cleared User/Pass = $user/$pass" 31 | echo "Cleared Docker = $docker_pass" 32 | echo "Cleared SSH = $ssh_pass" 33 | } 34 | -------------------------------------------------------------------------------- /src/test/jenkins/job/withCredentialsAndParameters.jenkins: -------------------------------------------------------------------------------- 1 | properties([ 2 | parameters([ 3 | booleanParam(name: 'myBooleanParam', description: 'My boolean typed parameter'), 4 | string(name: 'myStringParam', defaultValue: 'my default value', description: 'My string typed parameter') 5 | ]) 6 | ]) 7 | 8 | echo("'myStringParam' value is default: ${params.myStringParam}") 9 | 10 | withCredentials([string(credentialsId: 'my-gitlab-api-token', variable: 'GITLAB_API_TOKEN')]) { 11 | echo("'my-gitlab-api-token' credential variable value: ${GITLAB_API_TOKEN}") 12 | } 13 | -------------------------------------------------------------------------------- /src/test/jenkins/lib/properties.jenkins: -------------------------------------------------------------------------------- 1 | def map = [ 2 | key: "value", 3 | ] 4 | return map -------------------------------------------------------------------------------- /src/test/jenkins/lib/utils.jenkins: -------------------------------------------------------------------------------- 1 | #!groovy 2 | 3 | /** 4 | * Cleans a name and replaces all characters other than A-Za-z0-9 with "_", and all capitalizing all characters 5 | * @param s name to clean 6 | * @return clean name 7 | */ 8 | @NonCPS 9 | private static String cleanName(String s) { 10 | return s.replaceAll(/\W/, '_').toUpperCase() 11 | } 12 | 13 | /** 14 | * Returns the version of a property inside a maven pom. 15 | * To get the module version, use the "version" property name. 16 | * 17 | * If the property is defined twice in the pom, the first one will be returned. 18 | * 19 | * @param pom le chemin vers le pom 20 | * @param property name of the property to retrieve 21 | * @return the version 22 | */ 23 | def versionForPom(pom, property) { 24 | def matcher = readFile(pom) =~ "<$property>(.+)" 25 | matcher ? matcher[0][1] : null 26 | } 27 | 28 | /** 29 | * Returns the current scm revision. Be sure you are in a git context. 30 | * @return the sha1 of the revision (full format) 31 | */ 32 | String currentRevision() { 33 | return sh(returnStdout: true, script: 'git rev-parse HEAD').trim() 34 | } 35 | 36 | /** 37 | * Return a list of normalized pair of the form [repository, branch]. It works with any prefix like 38 | * refs/remotes/repo/branch, or repo/branch, etc. 39 | * 40 | * @param branchs a list of branch with any prefix (need at least to contain repository and branch) 41 | * @param repository the name of the repository 42 | * @return 43 | */ 44 | def getRepositoryBranchSplit(String[] branchs, String repository) { 45 | def branchSplits = [] 46 | for (int i = 0; i < branchs.length; i++) { 47 | def branch = branchs[i].trim() 48 | if (!branch.contains(repository)) { 49 | continue 50 | } 51 | def brancheWithRemote = branch.substring(branch.indexOf(repository)) 52 | branchSplits.add(brancheWithRemote.split("/")) 53 | } 54 | branchSplits 55 | } 56 | 57 | def getScmRevision(String remote, String ref) { 58 | return node() { 59 | checkout([ remote: remote, ref: ref]) 60 | currentRevision() 61 | } 62 | } 63 | 64 | def joinStrings(String... strings) { 65 | return strings.join(',') 66 | } 67 | 68 | // utils.groovy 69 | enum Color { 70 | GREEN, 71 | RED 72 | } 73 | 74 | // To be visible in the pipeline 75 | this.Color = Color 76 | 77 | return this 78 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestJenkinsFile_develop.txt: -------------------------------------------------------------------------------- 1 | Jenkinsfile.run() 2 | Jenkinsfile.stage(Build, groovy.lang.Closure) 3 | Jenkinsfile.node(groovy.lang.Closure) 4 | Jenkinsfile.checkout({$class=GitSCM, branches=[{name=develop}], extensions=[], userRemoteConfigs=[{credentialsId=gitlab_git_ssh, url=github.com/lesfurets/JenkinsPipelineUnit.git}]}) 5 | Jenkinsfile.echo(Running mvn verify on branch develop) 6 | Jenkinsfile.sh(mkdir -p ~/.gnupg) 7 | Jenkinsfile.file({credentialsId=gpg-pubring, variable=GPG_PUB_RING}) 8 | Jenkinsfile.file({credentialsId=gpg-secring, variable=GPG_SEC_RING}) 9 | Jenkinsfile.file({credentialsId=gradle-settings, variable=GRADLE_SETTINGS}) 10 | Jenkinsfile.withCredentials([GPG_PUB_RING, GPG_SEC_RING, GRADLE_SETTINGS], groovy.lang.Closure) 11 | Jenkinsfile.sh(./gradlew verify -P signing.secretKeyRingFile=GPG_SEC_RING -P extProps=GRADLE_SETTINGS) 12 | Jenkinsfile.archiveArtifacts(build/libs/*.jar) 13 | Jenkinsfile.archiveArtifacts(build/libs/*.asc) 14 | Jenkinsfile.junit({allowEmptyResults=true, testResults=build/test-results/test/*.xml}) 15 | Jenkinsfile.step({$class=WsCleanup}) 16 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestJenkinsFile_feature_.txt: -------------------------------------------------------------------------------- 1 | Jenkinsfile.run() 2 | Jenkinsfile.stage(Build, groovy.lang.Closure) 3 | Jenkinsfile.node(groovy.lang.Closure) 4 | Jenkinsfile.checkout({$class=GitSCM, branches=[{name=feature_}], extensions=[], userRemoteConfigs=[{credentialsId=gitlab_git_ssh, url=github.com/lesfurets/JenkinsPipelineUnit.git}]}) 5 | Jenkinsfile.echo(Running mvn verify on branch feature_) 6 | Jenkinsfile.sh(mkdir -p ~/.gnupg) 7 | Jenkinsfile.file({credentialsId=gpg-pubring, variable=GPG_PUB_RING}) 8 | Jenkinsfile.file({credentialsId=gpg-secring, variable=GPG_SEC_RING}) 9 | Jenkinsfile.file({credentialsId=gradle-settings, variable=GRADLE_SETTINGS}) 10 | Jenkinsfile.withCredentials([GPG_PUB_RING, GPG_SEC_RING, GRADLE_SETTINGS], groovy.lang.Closure) 11 | Jenkinsfile.sh(./gradlew verify -P signing.secretKeyRingFile=GPG_SEC_RING -P extProps=GRADLE_SETTINGS) 12 | Jenkinsfile.archiveArtifacts(build/libs/*.jar) 13 | Jenkinsfile.archiveArtifacts(build/libs/*.asc) 14 | Jenkinsfile.junit({allowEmptyResults=true, testResults=build/test-results/test/*.xml}) 15 | Jenkinsfile.step({$class=WsCleanup}) 16 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestJenkinsFile_master.txt: -------------------------------------------------------------------------------- 1 | Jenkinsfile.run() 2 | Jenkinsfile.stage(Build, groovy.lang.Closure) 3 | Jenkinsfile.node(groovy.lang.Closure) 4 | Jenkinsfile.checkout({$class=GitSCM, branches=[{name=master}], extensions=[], userRemoteConfigs=[{credentialsId=gitlab_git_ssh, url=github.com/lesfurets/JenkinsPipelineUnit.git}]}) 5 | Jenkinsfile.echo(Running mvn deploy on branch master) 6 | Jenkinsfile.sh(mkdir -p ~/.gnupg) 7 | Jenkinsfile.file({credentialsId=gpg-pubring, variable=GPG_PUB_RING}) 8 | Jenkinsfile.file({credentialsId=gpg-secring, variable=GPG_SEC_RING}) 9 | Jenkinsfile.file({credentialsId=gradle-settings, variable=GRADLE_SETTINGS}) 10 | Jenkinsfile.withCredentials([GPG_PUB_RING, GPG_SEC_RING, GRADLE_SETTINGS], groovy.lang.Closure) 11 | Jenkinsfile.sh(./gradlew deploy -P signing.secretKeyRingFile=GPG_SEC_RING -P extProps=GRADLE_SETTINGS) 12 | Jenkinsfile.archiveArtifacts(build/libs/*.jar) 13 | Jenkinsfile.archiveArtifacts(build/libs/*.asc) 14 | Jenkinsfile.archiveArtifacts(build/poms/*.xml) 15 | Jenkinsfile.archiveArtifacts(build/poms/*.asc) 16 | Jenkinsfile.junit({allowEmptyResults=true, testResults=build/test-results/test/*.xml}) 17 | Jenkinsfile.step({$class=WsCleanup}) 18 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestOneArgumentJob_should_run_script_with_one_argument.txt: -------------------------------------------------------------------------------- 1 | test_lib_call_with_null.run() 2 | test_lib_call_with_null.oneArg(Not null) 3 | oneArg.echo(Is not null) 4 | test_lib_call_with_null.oneArg(null) 5 | oneArg.echo(Is null) 6 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestParametersJob_parameters.txt: -------------------------------------------------------------------------------- 1 | parameters.run() 2 | parameters.booleanParam({name=myBooleanParam, description=My boolean typed parameter}) 3 | parameters.string({name=myStringParam, defaultValue=my default value, description=My string typed parameter}) 4 | parameters.parameters([null, null]) 5 | parameters.properties([null]) 6 | parameters.echo('myStringParam' value is default: my default value) 7 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestRegressionGlobalVar_globalVar.txt: -------------------------------------------------------------------------------- 1 | globalVar.run() 2 | globalVar.node(groovy.lang.Closure) 3 | globalVar.stage(One, groovy.lang.Closure) 4 | globalVar.echo(Stage One) 5 | globalVar.doWithProperties({PROP_1=VAL_1}) 6 | globalVar.stage(Two, groovy.lang.Closure) 7 | globalVar.echo(Stage Two) 8 | globalVar.doWithProperties({PROP_1=VAL_1, PROP_2=VAL_2}) 9 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestRegression_example.txt: -------------------------------------------------------------------------------- 1 | exampleJob.run() 2 | exampleJob.sleep(20) 3 | exampleJob.execute() 4 | exampleJob.node(groovy.lang.Closure) 5 | exampleJob.load(src/test/jenkins/lib/utils.jenkins) 6 | utils.run() 7 | exampleJob.load(src/test/jenkins/lib/properties.jenkins) 8 | properties.run() 9 | exampleJob.stage(Checkout, groovy.lang.Closure) 10 | exampleJob.checkout({$class=GitSCM, branches=[{name=feature_test}], extensions=[], userRemoteConfigs=[{credentialsId=gitlab_git_ssh, url=github.com/lesfurets/JenkinsPipelineUnit.git}]}) 11 | utils.currentRevision() 12 | utils.sh({returnStdout=true, script=git rev-parse HEAD}) 13 | exampleJob.gitlabBuilds({builds=[build, test]}, groovy.lang.Closure) 14 | exampleJob.stage(build, groovy.lang.Closure) 15 | exampleJob.gitlabCommitStatus(build, groovy.lang.Closure) 16 | exampleJob.sleep(20) 17 | exampleJob.sh(mvn clean package -DskipTests -DgitRevision=bcc19744) 18 | exampleJob.stage(test, groovy.lang.Closure) 19 | exampleJob.gitlabCommitStatus(test, groovy.lang.Closure) 20 | exampleJob.println(value) 21 | exampleJob.sh(mvn verify -DgitRevision=bcc19744) 22 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestWithCredentialsAndParametersJob_withCredentialsAndParameters.txt: -------------------------------------------------------------------------------- 1 | withCredentialsAndParameters.run() 2 | withCredentialsAndParameters.booleanParam({name=myBooleanParam, description=My boolean typed parameter}) 3 | withCredentialsAndParameters.string({name=myStringParam, defaultValue=my default value, description=My string typed parameter}) 4 | withCredentialsAndParameters.parameters([null, null]) 5 | withCredentialsAndParameters.properties([null]) 6 | withCredentialsAndParameters.echo('myStringParam' value is default: my default value) 7 | withCredentialsAndParameters.string({credentialsId=my-gitlab-api-token, variable=GITLAB_API_TOKEN}) 8 | withCredentialsAndParameters.withCredentials([GITLAB_API_TOKEN], groovy.lang.Closure) 9 | withCredentialsAndParameters.echo('my-gitlab-api-token' credential variable value: GITLAB_API_TOKEN) 10 | -------------------------------------------------------------------------------- /src/test/resources/callstacks/TestWithCredentialsJob_withCredentials.txt: -------------------------------------------------------------------------------- 1 | withCredentials.run() 2 | withCredentials.node(groovy.lang.Closure) 3 | withCredentials.usernamePassword({credentialsId=my_cred_id, usernameVariable=user, passwordVariable=pass}) 4 | withCredentials.string({credentialsId=docker_cred, variable=docker_pass}) 5 | withCredentials.string({credentialsId=ssh_cred, variable=ssh_pass}) 6 | withCredentials.withCredentials([[user, pass], docker_pass, ssh_pass], groovy.lang.Closure) 7 | withCredentials.echo(User/Pass = user/pass) 8 | withCredentials.echo(Docker = docker_pass) 9 | withCredentials.echo(SSH = ssh_pass) 10 | withCredentials.usernamePassword({credentialsId=my_cred_id, usernameVariable=user, passwordVariable=pass}) 11 | withCredentials.string({credentialsId=docker_cred, variable=docker_pass}) 12 | withCredentials.string({credentialsId=ssh_cred, variable=ssh_pass}) 13 | withCredentials.withCredentials([[user, pass], docker_pass, ssh_pass], groovy.lang.Closure) 14 | withCredentials.echo(Nested User/Pass = user/pass) 15 | withCredentials.echo(Nested Docker = docker_pass) 16 | withCredentials.echo(Nested SSH = ssh_pass) 17 | withCredentials.echo(Restored User/Pass = user/pass) 18 | withCredentials.echo(Restored Docker = docker_pass) 19 | withCredentials.echo(Restored SSH = ssh_pass) 20 | withCredentials.echo(Cleared User/Pass = null/null) 21 | withCredentials.echo(Cleared Docker = null) 22 | withCredentials.echo(Cleared SSH = null) 23 | -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/resources/net/courtanet/jenkins/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/JenkinsPipelineUnit/18fbbb546c3dba7faf1da9f1bbfe159ba7e599c1/src/test/resources/libs/commons@feature/resources/net/courtanet/jenkins/icon.png -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/resources/net/courtanet/jenkins/plaintext.iso-8859-1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/JenkinsPipelineUnit/18fbbb546c3dba7faf1da9f1bbfe159ba7e599c1/src/test/resources/libs/commons@feature/resources/net/courtanet/jenkins/plaintext.iso-8859-1.txt -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/resources/net/courtanet/jenkins/plaintext.utf8.txt: -------------------------------------------------------------------------------- 1 | 😃 -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/src/net/courtanet/jenkins/Utils2.groovy: -------------------------------------------------------------------------------- 1 | package net.courtanet.jenkins 2 | 3 | class Utils2 implements Serializable { 4 | 5 | def script 6 | 7 | Utils2() { 8 | 9 | } 10 | 11 | Utils2(script) { 12 | this.script = script 13 | } 14 | 15 | /** 16 | * @return GIT config for devteam-tools 17 | */ 18 | def gitTools() { 19 | return [branch: 'feature'] 20 | } 21 | 22 | static tools() { 23 | return "something" 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/vars/greetings.groovy: -------------------------------------------------------------------------------- 1 | // file: vars/greetings.groovy 2 | def call(body) { 3 | def config = [:] 4 | body.resolveStrategy = Closure.DELEGATE_FIRST 5 | body.delegate = config 6 | body() 7 | 8 | sayHello {} 9 | sayHello.hello("World!") 10 | } -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/vars/helloMessage.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Something like this in the job: 3 | * 4 | * helloTest { 5 | * message = "hello this is a test" 6 | * } 7 | * 8 | */ 9 | def call(body) { 10 | 11 | def config = [:] 12 | body.resolveStrategy = Closure.DELEGATE_FIRST 13 | body.delegate = config 14 | body() 15 | 16 | node { 17 | checkout scm 18 | echo "hello test message: ${config.message}" 19 | } 20 | } -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/vars/oneArg.groovy: -------------------------------------------------------------------------------- 1 | // file: vars/oneArg.groovy 2 | def call(arg) { 3 | echo arg ? "Is not null" : "Is null" 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/libs/commons@feature/vars/sayHello.groovy: -------------------------------------------------------------------------------- 1 | // file: vars/sayHello.groovy 2 | def call(body) { 3 | def config = [:] 4 | body.resolveStrategy = Closure.DELEGATE_FIRST 5 | body.delegate = config 6 | body() 7 | 8 | echo 'say Hello!' 9 | } 10 | 11 | def hello(name) { 12 | echo "Hello, ${name}" 13 | } -------------------------------------------------------------------------------- /src/test/resources/libs/commons@master/resources/net/courtanet/jenkins/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | courtanet 6 | pom 7 | Courtanet 8 | 9 | 10 | 5.14.9 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/libs/commons@master/src/net/courtanet/jenkins/Utils.groovy: -------------------------------------------------------------------------------- 1 | package net.courtanet.jenkins 2 | 3 | @Grab('org.apache.commons:commons-math3:3.6.1') 4 | import org.apache.commons.math3.primes.Primes 5 | 6 | class Utils implements Serializable { 7 | 8 | def script 9 | 10 | Utils() { 11 | 12 | } 13 | 14 | Utils(script) { 15 | this.script = script 16 | } 17 | 18 | void parallelize(int count) { 19 | if (!Primes.isPrime(count)) { 20 | echo "${count} was not prime" 21 | } 22 | // … 23 | } 24 | 25 | /** 26 | * @return GIT config for devteam-tools 27 | */ 28 | def gitTools() { 29 | return [branch: 'master'] 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/test/resources/libs/commons@master/vars/acme.groovy: -------------------------------------------------------------------------------- 1 | // vars/acme.groovy 2 | class acme implements Serializable { 3 | private String name = "something" 4 | def setName(value) { 5 | name = value 6 | } 7 | def getName() { 8 | name 9 | } 10 | def caution(message) { 11 | echo "Hello, ${name}! CAUTION: ${message}" 12 | } 13 | } -------------------------------------------------------------------------------- /src/test/resources/libs/commons@master/vars/sayHello.groovy: -------------------------------------------------------------------------------- 1 | // vars/sayHello.groovy 2 | def call(String name = 'name', String otherName = null) { 3 | // Any valid steps can be called from this code, just like in other 4 | // Scripted Pipeline 5 | echo "Hello, ${name}." 6 | if (otherName) { 7 | echo "Hello, ${otherName}." 8 | } 9 | } 10 | 11 | def call(String... args) { 12 | echo "$args" 13 | } -------------------------------------------------------------------------------- /src/test/resources/libs/env_var_not_defined/vars/envHelper.groovy: -------------------------------------------------------------------------------- 1 | 2 | def property1() { 3 | return "magic" 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/libs/params_not_accessible/src/org/test/LibClass.groovy: -------------------------------------------------------------------------------- 1 | package org.test 2 | 3 | class LibClass { 4 | def getX() { 5 | return testVar 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_as_var_arg_1/src/org/test/Monster1.groovy: -------------------------------------------------------------------------------- 1 | package org.test 2 | 3 | class Monster1 { 4 | String moniker 5 | 6 | Monster1(String m) { 7 | moniker = m 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_as_var_arg_1/vars/monster1.groovy: -------------------------------------------------------------------------------- 1 | import org.test.Monster1 2 | import org.test.extra.Monster2 3 | 4 | void call(Monster1 m1) { 5 | final m2 = new Monster2("Frankenstein's Monster") 6 | monster2 m2 7 | echo "$m1.moniker and $m2.moniker make quite a scary team" 8 | } 9 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_as_var_arg_2/src/org/test/extra/Monster2.groovy: -------------------------------------------------------------------------------- 1 | package org.test.extra 2 | 3 | class Monster2 { 4 | String moniker 5 | 6 | Monster2(String m) { 7 | moniker = m 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_as_var_arg_2/vars/monster2.groovy: -------------------------------------------------------------------------------- 1 | import org.test.extra.Monster2 2 | 3 | void call(Monster2 m2) { 4 | echo "$m2.moniker all by itself is frightening" 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_usage/src/org/test/ClassA.groovy: -------------------------------------------------------------------------------- 1 | package org.test 2 | 3 | class ClassA implements Serializable { 4 | def script = null 5 | ClassA() {} 6 | 7 | ClassA(script) { 8 | this.script = script 9 | } 10 | 11 | def fieldA = "I'm field of A" 12 | 13 | def methodA() { 14 | if (script) { 15 | script.sh("echo 'ClassA: $fieldA'") 16 | script.echo "env = $script.env" 17 | } else { 18 | sh("echo 'ClassA: $fieldA'") 19 | echo "env = $env" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_usage/src/org/test/ClassAB.groovy: -------------------------------------------------------------------------------- 1 | package org.test 2 | 3 | class ClassAB implements Serializable { 4 | def script = null 5 | ClassAB() {} 6 | ClassAB(script) { 7 | this.script = script 8 | } 9 | 10 | def methodAB() { 11 | if (script) { 12 | new ClassA(script).methodA() 13 | new ClassB(script).methodB() 14 | 15 | } else { 16 | new ClassA().methodA() 17 | new ClassB().methodB() 18 | } 19 | } 20 | 21 | def fieldAB = "I'm field of AB" 22 | 23 | def ownMethod() { 24 | if(script) { 25 | script.sh("echo 'ClassAB: $fieldAB'") 26 | script.echo "env = $script.env" 27 | } else { 28 | sh("echo 'ClassAB: $fieldAB'") 29 | echo "env = $env" 30 | } 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_class_usage/src/org/test/ClassB.groovy: -------------------------------------------------------------------------------- 1 | package org.test 2 | 3 | class ClassB implements Serializable { 4 | def script = null 5 | ClassB() {} 6 | ClassB(script) { 7 | this.script = script 8 | } 9 | 10 | def fieldB = "I'm field of B" 11 | 12 | def methodB() { 13 | if(script) { 14 | script.sh("echo 'ClassB: $fieldB'") 15 | } else { 16 | sh("echo 'ClassB: $fieldB'") 17 | } 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_vars_usage/src/org/test/LaClass.groovy: -------------------------------------------------------------------------------- 1 | package org.test 2 | 3 | class LaClass implements Serializable { 4 | 5 | def script 6 | 7 | LaClass() { 8 | 9 | } 10 | 11 | def callJenkinsSH(cmd) { 12 | sh("echo 'run $cmd with bash'") 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_vars_usage/vars/methodA.groovy: -------------------------------------------------------------------------------- 1 | def call() { 2 | echo "I'm A" 3 | echo "env = $env" 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_vars_usage/vars/methodAB.groovy: -------------------------------------------------------------------------------- 1 | def call() { 2 | methodA() 3 | methodB() 4 | echo "env = $env" 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/libs/test_cross_vars_usage/vars/methodB.groovy: -------------------------------------------------------------------------------- 1 | def call() { 2 | echo "I'm B" 3 | echo "env = $env" 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/test-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | courtanet 6 | pom 7 | Courtanet 8 | 9 | 10 | 5.14.9 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------