├── .github ├── CODEOWNERS ├── workflows │ ├── auto-merge-safe-deps.yml │ ├── close-bom-if-passing.yml │ ├── cd.yaml │ └── jenkins-security-scan.yml └── dependabot.yml ├── .git-blame-ignore-revs ├── .gitignore ├── .mvn ├── maven.config └── extensions.xml ├── src ├── test │ ├── resources │ │ └── org │ │ │ └── jenkinsci │ │ │ └── plugins │ │ │ └── workflow │ │ │ └── steps │ │ │ ├── TimeoutStepTest │ │ │ ├── serialForm │ │ │ │ ├── jobs │ │ │ │ │ └── timeout │ │ │ │ │ │ ├── nextBuildNumber │ │ │ │ │ │ ├── builds │ │ │ │ │ │ └── 1 │ │ │ │ │ │ │ ├── log-index │ │ │ │ │ │ │ ├── program.dat │ │ │ │ │ │ │ ├── workflow │ │ │ │ │ │ │ ├── 2.xml │ │ │ │ │ │ │ ├── 4.xml │ │ │ │ │ │ │ ├── 5.xml │ │ │ │ │ │ │ └── 3.xml │ │ │ │ │ │ │ ├── log │ │ │ │ │ │ │ └── build.xml │ │ │ │ │ │ └── config.xml │ │ │ │ └── org.jenkinsci.plugins.workflow.flow.FlowExecutionList.xml │ │ │ └── noImmediateForcibleTerminationOnResume.zip │ │ │ └── CatchErrorStepTest │ │ │ ├── serialFormWhenBuildResultOptionDidNotExist.zip │ │ │ └── serialFormWhenTypeOfBuildResultFieldWasResult.zip │ └── java │ │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── workflow │ │ └── steps │ │ ├── FileExistsStepTest.java │ │ ├── IsUnixStepTest.java │ │ ├── WithContextStepTest.java │ │ ├── PwdStepTest.java │ │ ├── EchoStepTest.java │ │ ├── SleepStepTest.java │ │ ├── UnstableStepTest.java │ │ ├── DeleteDirStepTest.java │ │ └── ArtifactArchiverStepTest.java └── main │ ├── resources │ ├── org │ │ └── jenkinsci │ │ │ └── plugins │ │ │ └── workflow │ │ │ ├── steps │ │ │ ├── MailStep │ │ │ │ ├── help-body.html │ │ │ │ ├── help-subject.html │ │ │ │ ├── help.html │ │ │ │ ├── help-bcc.html │ │ │ │ ├── help-cc.html │ │ │ │ ├── help-charset.html │ │ │ │ ├── help-mimeType.html │ │ │ │ ├── help-to.html │ │ │ │ ├── help-from.html │ │ │ │ ├── help-replyTo.html │ │ │ │ └── config.jelly │ │ │ ├── WriteFileStep │ │ │ │ ├── help-text.html │ │ │ │ ├── help-file.html │ │ │ │ ├── help.html │ │ │ │ ├── help-encoding.html │ │ │ │ └── config.jelly │ │ │ ├── EnvStep │ │ │ │ ├── config.properties │ │ │ │ ├── config.groovy │ │ │ │ ├── help-overrides.html │ │ │ │ └── help.html │ │ │ ├── PwdStep │ │ │ │ ├── help.html │ │ │ │ ├── help-tmp.html │ │ │ │ └── config.jelly │ │ │ ├── EchoStep │ │ │ │ ├── help-message.html │ │ │ │ └── config.jelly │ │ │ ├── SleepStep │ │ │ │ ├── help-time.html │ │ │ │ ├── help-unit.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── TimeoutStep │ │ │ │ ├── help-unit.html │ │ │ │ ├── help-time.html │ │ │ │ ├── help-activity.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── ErrorStep │ │ │ │ ├── help-message.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── ReadFileStep │ │ │ │ ├── help-file.html │ │ │ │ ├── help.html │ │ │ │ ├── help-encoding.html │ │ │ │ └── config.jelly │ │ │ ├── WaitForConditionStep │ │ │ │ ├── help-quiet.html │ │ │ │ ├── help-initialRecurrencePeriod.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── IsUnixStep │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── ToolStep │ │ │ │ ├── help-name.html │ │ │ │ ├── help-type.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── UnstableStep │ │ │ │ ├── help-message.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── ArtifactArchiverStep │ │ │ │ ├── help.html │ │ │ │ ├── help-includes.html │ │ │ │ ├── help-excludes.html │ │ │ │ └── config.jelly │ │ │ ├── WarnErrorStep │ │ │ │ ├── help-message.html │ │ │ │ ├── help.html │ │ │ │ ├── help-catchInterruptions.html │ │ │ │ └── config.jelly │ │ │ ├── GetContextStep │ │ │ │ ├── config.jelly │ │ │ │ └── help.html │ │ │ ├── WithContextStep │ │ │ │ ├── config.jelly │ │ │ │ └── help.html │ │ │ ├── CatchErrorStep │ │ │ │ ├── help-message.html │ │ │ │ ├── help-stageResult.html │ │ │ │ ├── help-buildResult.html │ │ │ │ ├── help-catchInterruptions.html │ │ │ │ ├── config.jelly │ │ │ │ └── help.html │ │ │ ├── RetryStep │ │ │ │ ├── help-conditions.html │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── DeleteDirStep │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── CoreStep │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── CoreWrapperStep │ │ │ │ ├── help.html │ │ │ │ └── config.jelly │ │ │ ├── Messages.properties │ │ │ ├── SynchronousResumeNotSupportedErrorCondition │ │ │ │ └── help.html │ │ │ ├── FileExistsStep │ │ │ │ ├── help.html │ │ │ │ ├── help-file.html │ │ │ │ └── config.jelly │ │ │ └── ArtifactUnarchiverStep │ │ │ │ └── config.jelly │ │ │ └── support │ │ │ └── steps │ │ │ └── stash │ │ │ ├── UnstashStep │ │ │ ├── help-name.html │ │ │ ├── help.html │ │ │ └── config.jelly │ │ │ └── StashStep │ │ │ ├── help-name.html │ │ │ ├── help-allowEmpty.html │ │ │ ├── help-useDefaultExcludes.html │ │ │ ├── help-excludes.html │ │ │ ├── help-includes.html │ │ │ ├── help.html │ │ │ └── config.jelly │ └── index.jelly │ └── java │ └── org │ └── jenkinsci │ └── plugins │ └── workflow │ ├── steps │ ├── ArtifactUnarchiverStep.java │ ├── PushdStep.java │ ├── SynchronousResumeNotSupportedErrorCondition.java │ ├── ArtifactArchiverStep.java │ ├── IsUnixStep.java │ ├── TimeoutStep.java │ ├── DeleteDirStep.java │ ├── ErrorStep.java │ ├── CatchExecutionOptions.java │ ├── ArtifactArchiverStepExecution.java │ ├── GetContextStep.java │ ├── EchoStep.java │ ├── FileExistsStep.java │ ├── ArtifactUnarchiverStepExecution.java │ ├── RetryStep.java │ ├── PwdStep.java │ ├── RetryStepExecution.java │ ├── UnstableStep.java │ ├── WithContextStep.java │ ├── WriteFileStep.java │ ├── WarnErrorStep.java │ ├── ReadFileStep.java │ └── SleepStep.java │ └── support │ └── steps │ └── stash │ ├── UnstashStep.java │ └── StashStep.java ├── Jenkinsfile ├── README.md └── CORE-STEPS.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/workflow-basic-steps-plugin-developers 2 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # #372 Spotless 2 | 349bccccbcaa8acf16e260ba440a30d0db9d875f 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | work 3 | .idea 4 | *.iml 5 | 6 | .classpath 7 | .project 8 | .settings/ 9 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s 4 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/nextBuildNumber: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-body.html: -------------------------------------------------------------------------------- 1 |
2 | Email body. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-subject.html: -------------------------------------------------------------------------------- 1 |
2 | Email subject line. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Simple step for sending email. 3 |
4 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/log-index: -------------------------------------------------------------------------------- 1 | 390 3 2 | 425 3 | 1025 5 4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WriteFileStep/help-text.html: -------------------------------------------------------------------------------- 1 |
2 | The data to write in the file. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/EnvStep/config.properties: -------------------------------------------------------------------------------- 1 | Environment\ variable\ overrides=Environment variable overrides 2 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/PwdStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Returns the current directory path as a string. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/EchoStep/help-message.html: -------------------------------------------------------------------------------- 1 |
2 | The message to write to the console output. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/SleepStep/help-time.html: -------------------------------------------------------------------------------- 1 |
2 | The length of time for which the step will sleep. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WriteFileStep/help-file.html: -------------------------------------------------------------------------------- 1 |
2 | Relative path of a file within the workspace. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/UnstashStep/help-name.html: -------------------------------------------------------------------------------- 1 |
2 | Name of a previously saved stash. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-bcc.html: -------------------------------------------------------------------------------- 1 |
2 | BCC email address list. Comma separated list of email addresses. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-cc.html: -------------------------------------------------------------------------------- 1 |
2 | CC email address list. Comma separated list of email addresses. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-charset.html: -------------------------------------------------------------------------------- 1 |
2 | Email body character encoding. Defaults to UTF-8 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-mimeType.html: -------------------------------------------------------------------------------- 1 |
2 | Email body MIME type. Defaults to text/plain. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-to.html: -------------------------------------------------------------------------------- 1 |
2 | To email address list. Comma separated list of email addresses. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WriteFileStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Write the given content to a named file in the current directory. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/SleepStep/help-unit.html: -------------------------------------------------------------------------------- 1 |
2 | The unit for the time parameter. Defaults to 'SECONDS' if not specified. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStep/help-unit.html: -------------------------------------------------------------------------------- 1 |
2 | The unit of the time parameter. Defaults to 'MINUTES' if not specified. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ErrorStep/help-message.html: -------------------------------------------------------------------------------- 1 |
2 | The message that will be logged to the console when an error is caught. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ReadFileStep/help-file.html: -------------------------------------------------------------------------------- 1 |
2 | Relative (/-separated) path to file within a workspace to read. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStep/help-time.html: -------------------------------------------------------------------------------- 1 |
2 | The length of time for which this step will wait before cancelling the nested block. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/help-name.html: -------------------------------------------------------------------------------- 1 |
2 | Name of a stash. 3 | Should be a simple identifier akin to a job name. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-from.html: -------------------------------------------------------------------------------- 1 |
2 | From email address. Defaults to the admin address globally configured for the Jenkins instance. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/UnstashStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Restores a set of files previously stashed into the current workspace. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/help-replyTo.html: -------------------------------------------------------------------------------- 1 |
2 | Reply-To email address. Defaults to the admin address globally configured for the Jenkins instance. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStep/help-activity.html: -------------------------------------------------------------------------------- 1 |
2 | Timeout after no activity in logs for this block instead of absolute duration. Defaults to false. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/help-quiet.html: -------------------------------------------------------------------------------- 1 |
2 | If true, the step does not log a message each time the condition is checked. Defaults to false. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/IsUnixStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Returns true if enclosing node is running on a Unix-like system (such as Linux or Mac OS X), false if Windows. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ReadFileStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Reads a file from a relative path (with root in current directory, usually workspace) and returns its content as a plain string. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ToolStep/help-name.html: -------------------------------------------------------------------------------- 1 |
2 | The name of the tool. The tool name must be pre-configured in Jenkins under Manage JenkinsGlobal Tool Configuration. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ToolStep/help-type.html: -------------------------------------------------------------------------------- 1 |
2 | Select the type from the available built-in tool providers. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/UnstableStep/help-message.html: -------------------------------------------------------------------------------- 1 |
2 | A message that will be logged to the console. The message will also be 3 | associated with the stage result and may be shown in visualizations. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/help-allowEmpty.html: -------------------------------------------------------------------------------- 1 |
2 | Create stash even if no files are included. If false (default), an error is raised when the stash does not contain files. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Archives build output artifacts for later use. 3 | As of Jenkins 2.x, this step is deprecated in favor of the more configurable archiveArtifacts. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WarnErrorStep/help-message.html: -------------------------------------------------------------------------------- 1 |
2 | A message that will be logged to the console if an error is caught. The 3 | message will also be associated with the stage result and may be shown in 4 | visualizations. 5 |
6 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/noImmediateForcibleTerminationOnResume.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/workflow-basic-steps-plugin/HEAD/src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/noImmediateForcibleTerminationOnResume.zip -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/program.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/workflow-basic-steps-plugin/HEAD/src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/program.dat -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/org.jenkinsci.plugins.workflow.flow.FlowExecutionList.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | timeout 5 | 1 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStep/help-includes.html: -------------------------------------------------------------------------------- 1 |
2 | Include artifacts matching this Ant style pattern. 3 | Use a comma separated list to add more than one expression. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ErrorStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Signals an error. 3 | Useful if you want to conditionally abort some part of your program. 4 | You can also just throw new Exception(), 5 | but this step will avoid printing a stack trace. 6 |
7 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStepTest/serialFormWhenBuildResultOptionDidNotExist.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/workflow-basic-steps-plugin/HEAD/src/test/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStepTest/serialFormWhenBuildResultOptionDidNotExist.zip -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/GetContextStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | No snippet generation supported. See inline help for usage. 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WithContextStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | No snippet generation supported. See inline help for usage. 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStepTest/serialFormWhenTypeOfBuildResultFieldWasResult.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/workflow-basic-steps-plugin/HEAD/src/test/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStepTest/serialFormWhenTypeOfBuildResultFieldWasResult.zip -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/help-message.html: -------------------------------------------------------------------------------- 1 |
2 | A message that will be logged to the console if an error is caught. If the 3 | stage result is specified, the message will also be associated with that 4 | result and may be shown in visualizations. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/UnstableStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Prints a message to the log and sets the overall build result and the stage 3 | result to UNSTABLE. The message will also be associated with 4 | the stage result and may be shown in visualizations. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/help-useDefaultExcludes.html: -------------------------------------------------------------------------------- 1 |
2 | If selected, use the default excludes from Ant - see 3 | here for the list. Defaults to true. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStep/help-excludes.html: -------------------------------------------------------------------------------- 1 |
2 | Exclude artifacts matching this Ant-style pattern.
3 | Use a comma-separated list to add more than one expression. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/EnvStep/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps.EnvStep 2 | f = namespace(lib.FormTagLib) 3 | f.entry(field: 'overrides', title: _('Environment variable overrides')) { 4 | f.textarea(value: instance == null ? '' : instance.overrides.join('\n')) 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-conditions.html: -------------------------------------------------------------------------------- 1 |
2 | Conditions under which the block should be retried. 3 | If none match, the block will fail. 4 | If there are no specified conditions, 5 | the block will always be retried except in case of user aborts. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/SleepStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Simply pauses the Pipeline build until the given amount of time has expired. 3 | Equivalent to (on Unix) sh 'sleep …'. 4 | May be used to pause one branch of parallel while another proceeds. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/help-initialRecurrencePeriod.html: -------------------------------------------------------------------------------- 1 |
2 | Sets the initial wait period, in milliseconds, between retries. Defaults to 250ms. 3 |
4 | Each failure will slow down the delay between attempts up to a maximum of 15 seconds. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ReadFileStep/help-encoding.html: -------------------------------------------------------------------------------- 1 |
2 | The encoding to use when reading the file. 3 | If left blank, the platform default encoding will be used. 4 | Binary files can be read into a Base64-encoded string by specifying "Base64" as the encoding. 5 |
6 | -------------------------------------------------------------------------------- /.github/workflows/auto-merge-safe-deps.yml: -------------------------------------------------------------------------------- 1 | name: Automatically approve and merge safe dependency updates 2 | on: 3 | - pull_request_target 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | jobs: 8 | auto-merge-safe-deps: 9 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/auto-merge-safe-deps.yml@v1 10 | -------------------------------------------------------------------------------- /.github/workflows/close-bom-if-passing.yml: -------------------------------------------------------------------------------- 1 | name: Close BOM update PR if passing 2 | on: 3 | check_run: 4 | types: 5 | - completed 6 | permissions: 7 | contents: read 8 | pull-requests: write 9 | jobs: 10 | close-bom-if-passing: 11 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/close-bom-if-passing.yml@v1 12 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/workflow/2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/DeleteDirStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Recursively deletes the current directory and its contents. 3 | Symbolic links and junctions will not be followed but will be removed. 4 | To delete a specific directory of a workspace wrap the deleteDir 5 | step in a dir step. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WriteFileStep/help-encoding.html: -------------------------------------------------------------------------------- 1 |
2 | The target encoding for the file. 3 | If left blank, the platform default encoding will be used. 4 | If the text is a Base64-encoded string, the decoded binary data can be written 5 | to the file by specifying "Base64" as the encoding. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/help-excludes.html: -------------------------------------------------------------------------------- 1 |
2 | Optional set of Ant-style exclude patterns.
3 | Use a comma separated list to add more than one expression.
4 | If blank, no files will be excluded. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Retry the block (up to N times) if any exception happens during its body execution. 3 | If an exception happens on the final attempt then it will lead to aborting the build (unless it is caught and processed somehow). 4 | User aborts of the build are not caught. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Executes the code inside the block with a determined time out limit. 3 | If the time limit is reached, an exception (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) is thrown, which leads to aborting 4 | the build (unless it is caught and processed somehow). 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ToolStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Binds a tool installation to a variable (the tool home directory is returned). 3 | Only tools already configured in Configure System are available here. If the original tool installer 4 | has the auto-provision feature, then the tool will be installed as required. 5 |
6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "maven" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/help-stageResult.html: -------------------------------------------------------------------------------- 1 |
2 | If an error is caught, the stage result will be set to this value. If a 3 | message was specified, the message will be associated with this result. 4 | Use SUCCESS or null to keep the stage result from 5 | being set when an error is caught. 6 |
7 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | See the documentation for more options: 3 | 4 | https://github.com/jenkins-infra/pipeline-library/ 5 | 6 | */ 7 | buildPlugin( 8 | useContainerAgent: true, // Set to `false` if you need to use Docker for containerized tests 9 | configurations: [ 10 | [platform: 'linux', jdk: 21], 11 | [platform: 'windows', jdk: 17], 12 | [platform: 'linux', jdk: 25], 13 | ]) 14 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/EnvStep/help-overrides.html: -------------------------------------------------------------------------------- 1 |
2 | A list of environment variables to set, each in the form VARIABLE=value 3 | or VARIABLE= to unset variables otherwise defined. 4 | You may also use the syntax PATH+WHATEVER=/something 5 | to prepend /something to $PATH. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/GetContextStep/help.html: -------------------------------------------------------------------------------- 1 |

2 | Obtains a contextual object as in StepContext.get; cf. withContext. 3 | Takes a single type argument. Example: 4 |

5 |
getContext hudson.FilePath
6 |

7 | For use from trusted code, such as global libraries, which can manipulate internal Jenkins APIs. 8 |

9 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.13 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CoreStep/help.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | This is a special step that allows to call builders or post-build actions (as in freestyle or similar projects), in general "build steps". 4 | Just select the build step to call from the dropdown list and configure it as needed. 5 |

6 |

7 | Note that only Pipeline-compatible steps will be shown in the list. 8 |

9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Runs its body repeatedly until it returns true. 3 | If it returns false, waits a while and tries again. 4 | (Subsequent failures will slow down the delay between attempts up to a maximum of 15 seconds.) 5 | There is no limit to the number of retries, 6 | but if the body throws an error that is thrown up immediately. 7 |
8 | -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | maven-cd: 12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 13 | secrets: 14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} 16 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/help-buildResult.html: -------------------------------------------------------------------------------- 1 |
2 | If an error is caught, the overall build result will be set to this value. 3 | Note that the build result can only get worse, so you cannot change the result 4 | to SUCCESS if the current result is UNSTABLE or worse. 5 | Use SUCCESS or null to keep the build result from 6 | being set when an error is caught. 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/PwdStep/help-tmp.html: -------------------------------------------------------------------------------- 1 |
2 | If selected, return a temporary directory associated with the current directory path rather than the directory path itself. 3 | The return value is different for each current directory. No two directories share the same temporary directory. 4 | This is an appropriate place to put temporary files which should not clutter a source checkout; 5 | local repositories or caches; etc. Defaults to false. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CoreWrapperStep/help.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | This is a special step that allows to call build wrappers (also called "Environment Configuration" in freestyle or similar projects). 4 | Just select the wrapper to use from the dropdown list and configure it as needed. Everything inside the wrapper block is under its effect. 5 |

6 |

7 | Note that only Pipeline-compatible wrappers will be shown in the list. 8 |

9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WarnErrorStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Executes its body, and if an exception is thrown, sets the overall build result 3 | and the stage result to UNSTABLE, prints a specified message and 4 | the thrown exception to the build log, and associates the stage result with the 5 | message so that it can be displayed by visualizations. 6 |

Equivalent to catchError(message: message, buildResult: 'UNSTABLE', stageResult: 'UNSTABLE'). 7 |

8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/help-catchInterruptions.html: -------------------------------------------------------------------------------- 1 |
2 | If true, certain types of exceptions that are used to interrupt the flow of 3 | execution for Pipelines will be caught and handled by the step. If false, 4 | those types of exceptions will be caught and immediately rethrown. Examples 5 | of these types of exceptions include those thrown when a build is manually 6 | aborted through the UI and those thrown by the timeout step. Defaults to true. 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WarnErrorStep/help-catchInterruptions.html: -------------------------------------------------------------------------------- 1 |
2 | If true, certain types of exceptions that are used to interrupt the flow of 3 | execution for Pipelines will be caught and handled by the step. If false, 4 | those types of exceptions will be caught and immediately rethrown. Examples 5 | of these types of exceptions include those thrown when a build is manually 6 | aborted through the UI and those thrown by the timeout step. Defaults to true. 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/Messages.properties: -------------------------------------------------------------------------------- 1 | ArtifactArchiverStepExecution.Deprecated=The archive step is deprecated, please use archiveArtifacts instead. 2 | ArtifactArchiverStepExecution.NoFiles=No files found to archive for pattern "{0}"; continuing. 3 | ArtifactArchiverStepExecution.NoFilesWithExcludes=No files found to archive for pattern "{0}", excluding "{1}"; continuing. 4 | FileExistsStep.EmptyString=The fileExists step was called with a null or empty string, so the current directory will be checked instead. 5 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 10 | true 11 | 12 | 13 | false 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/workflow/4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 3 6 | 7 | 4 8 | org.jenkinsci.plugins.workflow.steps.TimeoutStep 9 | 10 | 11 | 12 | 13 | 1547839656316 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ opened, synchronize, reopened ] 9 | workflow_dispatch: 10 | 11 | permissions: 12 | security-events: write 13 | contents: read 14 | actions: read 15 | 16 | jobs: 17 | security-scan: 18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 19 | with: 20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 22 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/help-includes.html: -------------------------------------------------------------------------------- 1 |
2 | Optional set of Ant-style include patterns.
3 | Use a comma separated list to add more than one expression.
4 | If blank, treated like **: all files.
5 | The current working directory is the base directory for the saved files, 6 | which will later be restored in the same relative locations, 7 | so if you want to use a subdirectory wrap this in dir. 8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/SynchronousResumeNotSupportedErrorCondition/help.html: -------------------------------------------------------------------------------- 1 |
2 | The Jenkins controller was restarted while the build was running a step which cannot be resumed. 3 | Some steps like sh or input are written to survive a Jenkins restart 4 | and simply pick up where they left off when the build resumes. 5 | Others like checkout or junit normally complete promptly but cannot tolerate a restart. 6 | In case one of these steps happened to be in progress when Jenkins shut down, 7 | the resumed build will throw an error; 8 | using this condition with retry allows the step (or the whole enclosing node block) to be rerun. 9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/EnvStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Sets one or more environment variables within a block. 3 | The names of environment variables are case-insensitive but case-preserving, that is, setting `Foo` will change the value of `FOO` if it already exists. 4 | Environment variables are available to any external processes spawned within that scope. 5 | For example: 6 |

 7 | node {
 8 |   withEnv(['MYTOOL_HOME=/usr/local/mytool']) {
 9 |     sh '$MYTOOL_HOME/bin/start'
10 |   }
11 | }
12 | 
13 |

(Note that here we are using single quotes in Groovy, so the variable expansion is being done by the Bourne shell, not Jenkins.) 14 |

See the documentation for the env singleton for more information on environment variables. 15 |

16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pipeline: Basic Steps Plugin 2 | 3 | ## Introduction 4 | 5 | Commonly used steps for Pipelines. General Jenkins Pipeline documentation is available in the [Pipeline chapter](https://www.jenkins.io/doc/book/pipeline/) of the [User Handbook](https://www.jenkins.io/doc/book/getting-started/). 6 | 7 | The [Pipeline steps reference](https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/) describes the Pipeline steps provided by this plugin. 8 | 9 | The [Pipeline solutions page](https://www.jenkins.io/solutions/pipeline/) provides videos, tutorials, and other Pipeline resources. 10 | 11 | ## Version History 12 | 13 | New versions use [GitHub Releases](https://github.com/jenkinsci/workflow-basic-steps-plugin/releases). 14 | See also the [archive](https://github.com/jenkinsci/workflow-basic-steps-plugin/blob/bed5ff08317e278d5d8cb15105b6579911568f8c/CHANGELOG.md). 15 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WithContextStep/help.html: -------------------------------------------------------------------------------- 1 |

2 | Wraps a block in a contextual object as in BodyInvoker.withContext; cf. getContext. 3 | Takes a single context argument plus a block. Example: 4 |

5 |
withContext(new MyConsoleLogFilter()) {
 6 |     sh 'process'
 7 | }
8 |

9 | Automatically merges its argument with contextual objects in the case of ConsoleLogFilter, LauncherDecorator, and EnvironmentExpander. 10 |

11 |

12 | For use from trusted code, such as global libraries, which can manipulate internal Jenkins APIs. 13 |

14 |

15 | Do not attempt to pass objects defined in Groovy; 16 | only Java-defined objects are supported. 17 | Really you should avoid using this and getContext and just define a Step in a plugin instead. 18 |

19 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/FileExistsStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Checks if the given file exists on the current node. 3 | Returns true | false. 4 | 5 | This step must be run inside a node context: 6 |

 7 | # Scripted Syntax
 8 | node {
 9 |     if (fileExists('src/main/resources/index.html')) {
10 |         echo "File src/main/resources/index.html found!"
11 |     }
12 | }
13 | 

14 | 15 | With the Declarative Syntax, it must be run in a stage with a defined agent (e.g. different than `agent none`): 16 | 17 |

18 | # Declarative Syntax
19 | stage ('Check for existence of index.html') {
20 |     agent any # Could be a top-level directive or a stage level directive
21 |     steps {
22 |         script {
23 |             if (fileExists('src/main/resources/index.html')) {
24 |                 echo "File src/main/resources/index.html found!"
25 |             }
26 |         }
27 |     }
28 | }
29 | 

30 |
31 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/FileExistsStep/help-file.html: -------------------------------------------------------------------------------- 1 |
2 | Path to a file or a directory to verify its existence. 3 | 28 |
29 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/workflow/5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 4 6 | 7 | 5 8 | org.jenkinsci.plugins.workflow.steps.SleepStep 9 | 10 | 11 | 12 | 13 | 14 | unit 15 | MINUTES 16 | 17 | 18 | time 19 | 2 20 | 21 | 22 | true 23 | 24 | 25 | 1547839656427 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/workflow/3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | 7 | 3 8 | org.jenkinsci.plugins.workflow.steps.TimeoutStep 9 | 10 | 11 | 12 | 13 | 14 | unit 15 | DAYS 16 | 17 | 18 | time 19 | 9999999 20 | 21 | 22 | true 23 | 24 | 25 | 1547839656279 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/log: -------------------------------------------------------------------------------- 1 | Started by user unknown or anonymous 2 | Running in Durability level: MAX_SURVIVABILITY 3 | ha:////4Bni0Kg595B773GNHBf3LOfNzFS0Zy2oHGlgTJqu8JzJAAAApR+LCAAAAAAAAP9tjTEOwjAUQ3+KOrAycohUghExsUZZOEFIQkgb/d8mKe3EibgadyBQiQlLlmxL1nu+oE4RjhQdby12HpP2vA+jK4lPFLtroIm3dOGaMFGwXNpJkrGnpUrKFhaxClYC1hZ1oOTRZdiIVt1VExS65pxj2Q4CKm8GeAAThZxVzN8yR9jeRpMIf5y/AJj7DGxXvP/86jduZBmjwAAAAA==[Pipeline] timeout 4 | Timeout set to expire in 27,397 yr 5 | ha:////4IU52GY073uu+2jSm37gmpAJWJzM2ywcQP9uho5Af3faAAAApR+LCAAAAAAAAP9tjTEOwjAUQ3+KOrAycoh0gA0xsUZZOEFIQkgb/d8mKe3EibgadyBQiQlLlmxL1nu+oE4RjhQdby12HpP2vA+jK4lPFLtroIm3dOGaMFGwXNpJkrGnpUrKFhaxClYC1hZ1oOTRZdiIVt1VExS65pxj2Q4CKm8GeAAThZxVzN8yR9jeRpMIf5y/AJj7DGxXvP/86jfoP95RwAAAAA==[Pipeline] { 6 | ha:////4PdVo1HbA0DesxIdO8NS1GmQ6F8AObu5xGodRykun6vdAAAAoh+LCAAAAAAAAP9tjTEOAiEURD9rLGwtPQTbaGWsbAmNJ0AWEZb8zwLrbuWJvJp3kLiJlZNMMm+a93rDOic4UbLcG+wdZu14DKOti0+U+lugiXu6ck2YKRguzSSpM+cFJRUDS1gDKwEbgzpQdmgLbIVXD9UGhba9lFS/o4DGdQM8gYlqLiqVL8wJdvexy4Q/z18BzLEA29ce4gdpL1fxvAAAAA==[Pipeline] sleep 7 | Sleeping for 2 min 0 sec 8 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 |
28 | Commonly used steps for Pipelines. 29 |
30 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/IsUnixStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/DeleteDirStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/EchoStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ErrorStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/PwdStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/UnstableStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/UnstashStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CoreStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/FileExistsStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CoreWrapperStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ToolStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/SleepStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ReadFileStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WarnErrorStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/FileExistsStepTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 4 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.RegisterExtension; 7 | import org.jvnet.hudson.test.Issue; 8 | import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; 9 | import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension; 10 | 11 | class FileExistsStepTest { 12 | 13 | @SuppressWarnings("unused") 14 | @RegisterExtension 15 | private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); 16 | 17 | @RegisterExtension 18 | private final JenkinsSessionExtension sessions = new JenkinsSessionExtension(); 19 | 20 | @Issue("JENKINS-48138") 21 | @Test 22 | void emptyStringWarning() throws Throwable { 23 | sessions.then(j -> { 24 | WorkflowJob p = j.createProject(WorkflowJob.class, "p"); 25 | p.setDefinition(new CpsFlowDefinition("node { fileExists('') }", true)); 26 | j.assertLogContains(Messages.FileExistsStep_EmptyString(), j.buildAndAssertSuccess(p)); 27 | }); 28 | } 29 | 30 | @Test 31 | void nullStringWarning() throws Throwable { 32 | sessions.then(j -> { 33 | WorkflowJob p = j.createProject(WorkflowJob.class, "p"); 34 | p.setDefinition(new CpsFlowDefinition("node { fileExists(null) }", true)); 35 | j.assertLogContains(Messages.FileExistsStep_EmptyString(), j.buildAndAssertSuccess(p)); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | Saves a set of files for later use on any node/workspace in the same Pipeline run. 3 | By default, stashed files are discarded at the end of a pipeline run. 4 | Other plugins may change this behavior to preserve stashes for longer. 5 | For example, Declarative Pipeline includes a preserveStashes() option 6 | to allow stashes from a run to be retained and used if that run is restarted. 7 |
8 | Stashes from one Pipeline run are not available in other runs, other Pipelines, or other jobs. 9 | If you want to persist artifacts for use outside of a single run, consider using 10 | 11 | archiveArtifacts instead. 12 | Note that the stash and unstash steps are designed for use with small files. 13 | For large data transfers, use the External Workspace Manager plugin, 14 | or use an external repository manager such as Nexus or Artifactory. 15 | This is because stashed files are archived in a compressed TAR, and with large files this demands considerable 16 | resources on the controller, particularly CPU time. 17 | There's not a hard stash size limit, but between 5-100 MB you should probably consider alternatives. 18 | If you use the Artifact Manager on S3 plugin, or another plugin with a remote atifact manager, 19 | you can use this step without affecting controller performance 20 | since stashes will be sent directly to S3 from the agent (and similarly for unstash). 21 |
22 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/WriteFileStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/workflow/steps/TimeoutStepTest/serialForm/jobs/timeout/builds/1/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1 9 | 10 | 11 | 12 | 13 | 1 14 | 1547839655961 15 | 1547839655963 16 | 0 17 | UTF-8 18 | false 19 | 20 | SUCCESS 21 | 24 | 25 | MAX_SURVIVABILITY 26 | 27 | 28 | flowNode 29 | 20637465 30 | 31 | 32 | classLoad 33 | 57883475 34 | 35 | 36 | run 37 | 299403380 38 | 39 | 40 | parse 41 | 83564469 42 | 43 | 44 | saveProgram 45 | 101383291 46 | 47 | 48 | true 49 | 5 50 | 1:5 51 | 2 52 | false 53 | false 54 | 55 | false 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/ArtifactUnarchiverStep.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import hudson.FilePath; 6 | import hudson.model.Run; 7 | import hudson.model.TaskListener; 8 | import java.util.Collections; 9 | import java.util.HashSet; 10 | import java.util.Map; 11 | import java.util.Set; 12 | import org.kohsuke.stapler.DataBoundConstructor; 13 | import org.kohsuke.stapler.DataBoundSetter; 14 | 15 | /** 16 | * @author Kohsuke Kawaguchi 17 | */ 18 | public class ArtifactUnarchiverStep extends Step { 19 | /** 20 | * Files to copy over. 21 | */ 22 | @DataBoundSetter 23 | public Map mapping; 24 | 25 | // TBD: alternate single-file option value ~ Collections.singletonMap(value, value) 26 | 27 | @DataBoundConstructor 28 | public ArtifactUnarchiverStep() {} 29 | 30 | @Override 31 | public StepExecution start(StepContext context) throws Exception { 32 | return new ArtifactUnarchiverStepExecution(mapping, context); 33 | } 34 | 35 | @Extension 36 | public static class DescriptorImpl extends StepDescriptor { 37 | 38 | @Override 39 | public String getFunctionName() { 40 | return "unarchive"; 41 | } 42 | 43 | @NonNull 44 | @Override 45 | public String getDisplayName() { 46 | return "Copy archived artifacts into the workspace"; 47 | } 48 | 49 | @Override 50 | public boolean isAdvanced() { 51 | return true; 52 | } 53 | 54 | @Override 55 | public Set> getRequiredContext() { 56 | Set> context = new HashSet<>(); 57 | Collections.addAll(context, FilePath.class, Run.class, TaskListener.class); 58 | return Collections.unmodifiableSet(context); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/PushdStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | /** 28 | * @deprecated Only exists as a placeholder for old running builds; now {@code org.jenkinsci.plugins.workflow.support.steps.PushdStep}. 29 | */ 30 | @Deprecated 31 | public class PushdStep { 32 | 33 | private PushdStep() {} 34 | 35 | public static class Execution extends AbstractStepExecutionImpl { 36 | 37 | private Execution() { 38 | throw new AssertionError("only deserialized"); 39 | } 40 | 41 | @Override 42 | public boolean start() throws Exception { 43 | throw new AssertionError("only deserialized"); 44 | } 45 | 46 | @Override 47 | public void onResume() {} 48 | 49 | private static final long serialVersionUID = 1L; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/ArtifactUnarchiverStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 |

30 | Currently no visual configuration. 31 | May take a mapping parameter which is a map from artifact names (files, directories ending in /, or any other Ant patternsets), 32 | to workspace destination names. 33 | For example to copy one file: 34 |

35 |
unarchive mapping: ['target/my.war': 'here.war']
36 |

37 | To copy a whole directory: 38 |

39 |
unarchive mapping: ['dir/' : '.']
40 | sh 'cat dir/file'
41 |

42 | Replaced for most purposes by stash and unstash. 43 |

44 |
45 |
46 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/IsUnixStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 28 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 29 | import org.junit.jupiter.api.BeforeEach; 30 | import org.junit.jupiter.api.Test; 31 | import org.jvnet.hudson.test.JenkinsRule; 32 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 33 | 34 | @WithJenkins 35 | class IsUnixStepTest { 36 | 37 | private JenkinsRule r; 38 | 39 | @BeforeEach 40 | void beforeEach(JenkinsRule rule) { 41 | r = rule; 42 | } 43 | 44 | @Test 45 | void basics() throws Exception { 46 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 47 | p.setDefinition(new CpsFlowDefinition( 48 | "def xsh(cmd) {if (isUnix()) {sh cmd} else {bat cmd}}; node {xsh 'echo hello world'}", true)); 49 | r.assertLogContains("hello world", r.assertBuildStatusSuccess(p.scheduleBuild2(0))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/MailStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/SynchronousResumeNotSupportedErrorCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2022 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import hudson.Extension; 28 | import java.io.IOException; 29 | import org.jenkinsci.Symbol; 30 | import org.jenkinsci.plugins.workflow.flow.ErrorCondition; 31 | import org.kohsuke.stapler.DataBoundConstructor; 32 | 33 | /** 34 | * Checks for {@link SynchronousResumeNotSupportedException}. 35 | */ 36 | public final class SynchronousResumeNotSupportedErrorCondition extends ErrorCondition { 37 | 38 | @DataBoundConstructor 39 | public SynchronousResumeNotSupportedErrorCondition() {} 40 | 41 | @Override 42 | public boolean test(Throwable error, StepContext context) throws IOException, InterruptedException { 43 | return error instanceof SynchronousResumeNotSupportedException; 44 | } 45 | 46 | @Symbol("nonresumable") 47 | @Extension 48 | public static final class DescriptorImpl extends ErrorConditionDescriptor { 49 | 50 | @Override 51 | public String getDisplayName() { 52 | return "Non-resumable steps"; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStep.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import hudson.FilePath; 6 | import hudson.Launcher; 7 | import hudson.Util; 8 | import hudson.model.Run; 9 | import hudson.model.TaskListener; 10 | import java.util.Collections; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | import org.kohsuke.stapler.DataBoundConstructor; 14 | import org.kohsuke.stapler.DataBoundSetter; 15 | 16 | /** 17 | * Artifact archiving. 18 | * 19 | * @author Kohsuke Kawaguchi 20 | */ 21 | public class ArtifactArchiverStep extends Step { 22 | 23 | private final String includes; 24 | private String excludes; 25 | 26 | @DataBoundConstructor 27 | public ArtifactArchiverStep(String includes) { 28 | this.includes = includes; 29 | } 30 | 31 | public String getIncludes() { 32 | return includes; 33 | } 34 | 35 | public String getExcludes() { 36 | return excludes; 37 | } 38 | 39 | @DataBoundSetter 40 | public void setExcludes(String excludes) { 41 | this.excludes = Util.fixEmptyAndTrim(excludes); 42 | } 43 | 44 | @Override 45 | public StepExecution start(StepContext context) throws Exception { 46 | return new ArtifactArchiverStepExecution(this, context); 47 | } 48 | 49 | @Extension 50 | public static class DescriptorImpl extends StepDescriptor { 51 | 52 | @Override 53 | public String getFunctionName() { 54 | return "archive"; 55 | } 56 | 57 | @NonNull 58 | @Override 59 | public String getDisplayName() { 60 | return "Archive artifacts"; 61 | } 62 | 63 | /** 64 | * When the {@code archiveArtifacts} symbol is available, {@link CoreStep} may be used instead, 65 | * with no more verbose a syntax but more configuration options. 66 | */ 67 | @Override 68 | public boolean isAdvanced() { 69 | return true; 70 | } 71 | 72 | @Override 73 | public Set> getRequiredContext() { 74 | Set> context = new HashSet<>(); 75 | Collections.addAll(context, FilePath.class, Run.class, Launcher.class, TaskListener.class); 76 | return Collections.unmodifiableSet(context); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/help.html: -------------------------------------------------------------------------------- 1 |
2 | If the body throws an exception, mark the build as a failure, but nonetheless 3 | continue to execute the Pipeline from the statement following the catchError step. 4 | The behavior of the step when an exception is thrown can be configured to print 5 | a message, set a build result other than failure, change the stage result, 6 | or ignore certain kinds of exceptions that are used to interrupt the build. 7 |

This step is most useful when used in Declarative Pipeline or with the 8 | options to set the stage result or ignore build interruptions. Otherwise, 9 | consider using plain try-catch(-finally) blocks. 10 | It is also useful when using certain post-build actions (notifiers) 11 | originally defined for freestyle projects which pay attention to the result of the ongoing build. 12 |

13 | node {
14 |     catchError {
15 |         sh 'might fail'
16 |     }
17 |     step([$class: 'Mailer', recipients: 'admin@somewhere'])
18 | }
19 | 
20 |

If the shell step fails, the Pipeline build’s status will be set to failed, so that the subsequent mail step will see that this build is failed. 21 | In the case of the mail sender, this means that it will send mail. 22 | (It may also send mail if this build succeeded but previous ones failed, and so on.) 23 | Even in that case, this step can be replaced by the following idiom: 24 |

25 | node {
26 |     try {
27 |         sh 'might fail'
28 |     } catch (err) {
29 |         echo "Caught: ${err}"
30 |         currentBuild.result = 'FAILURE'
31 |     }
32 |     step([$class: 'Mailer', recipients: 'admin@somewhere'])
33 | }
34 | 
35 |

For other cases, plain try-catch(-finally) blocks may be used: 36 |

37 | node {
38 |     sh './set-up.sh'
39 |     try {
40 |         sh 'might fail'
41 |         echo 'Succeeded!'
42 |     } catch (err) {
43 |         echo "Failed: ${err}"
44 |     } finally {
45 |         sh './tear-down.sh'
46 |     }
47 |     echo 'Printed whether above succeeded or failed.'
48 | }
49 | // …and the pipeline as a whole succeeds
50 | 
51 |

See this document for background. 52 |

53 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/WithContextStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; 28 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 29 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 30 | import org.junit.jupiter.api.BeforeEach; 31 | import org.junit.jupiter.api.Test; 32 | import org.junit.jupiter.api.extension.RegisterExtension; 33 | import org.jvnet.hudson.test.JenkinsRule; 34 | import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; 35 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 36 | 37 | @WithJenkins 38 | class WithContextStepTest { 39 | 40 | @SuppressWarnings("unused") 41 | @RegisterExtension 42 | private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); 43 | 44 | private JenkinsRule r; 45 | 46 | @BeforeEach 47 | void beforeEach(JenkinsRule rule) { 48 | r = rule; 49 | } 50 | 51 | @Test 52 | void pushd() throws Exception { 53 | WorkflowJob p = r.createProject(WorkflowJob.class, "p"); 54 | ScriptApproval.get().approveSignature("method hudson.FilePath child java.lang.String"); 55 | p.setDefinition(new CpsFlowDefinition( 56 | "node {withContext(getContext(hudson.FilePath).child('subdir')) {echo(/simulating dir step in ${pwd()}/)}}", 57 | true)); 58 | r.assertLogContains( 59 | "simulating dir step in " 60 | + r.jenkins.getWorkspaceFor(p).child("subdir").getRemote(), 61 | r.buildAndAssertSuccess(p)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/IsUnixStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.Launcher; 30 | import java.util.Collections; 31 | import java.util.Set; 32 | import org.kohsuke.stapler.DataBoundConstructor; 33 | 34 | /** 35 | * Checks whether we are running on Unix. 36 | */ 37 | public class IsUnixStep extends Step { 38 | 39 | @DataBoundConstructor 40 | public IsUnixStep() {} 41 | 42 | @Override 43 | public StepExecution start(StepContext context) throws Exception { 44 | return new Execution(context); 45 | } 46 | 47 | public static class Execution extends SynchronousStepExecution { 48 | 49 | Execution(StepContext context) { 50 | super(context); 51 | } 52 | 53 | @Override 54 | protected Boolean run() throws Exception { 55 | return getContext().get(Launcher.class).isUnix(); 56 | } 57 | 58 | private static final long serialVersionUID = 1L; 59 | } 60 | 61 | @Extension 62 | public static final class DescriptorImpl extends StepDescriptor { 63 | 64 | @Override 65 | public String getFunctionName() { 66 | return "isUnix"; 67 | } 68 | 69 | @NonNull 70 | @Override 71 | public String getDisplayName() { 72 | return "Checks if running on a Unix-like node"; 73 | } 74 | 75 | @Override 76 | public Set> getRequiredContext() { 77 | return Collections.singleton(Launcher.class); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/TimeoutStep.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.Extension; 5 | import hudson.model.TaskListener; 6 | import hudson.util.ListBoxModel; 7 | import java.io.Serializable; 8 | import java.util.Collections; 9 | import java.util.Set; 10 | import java.util.concurrent.TimeUnit; 11 | import org.kohsuke.stapler.DataBoundConstructor; 12 | import org.kohsuke.stapler.DataBoundSetter; 13 | 14 | /** 15 | * Executes the body with a timeout, which will kill the body. 16 | * 17 | * @author Kohsuke Kawaguchi 18 | */ 19 | public class TimeoutStep extends Step implements Serializable { 20 | 21 | private final int time; 22 | 23 | private TimeUnit unit = TimeUnit.MINUTES; 24 | 25 | private boolean activity = false; 26 | 27 | @DataBoundConstructor 28 | public TimeoutStep(int time) { 29 | this.time = time; 30 | } 31 | 32 | @DataBoundSetter 33 | public void setUnit(TimeUnit unit) { 34 | this.unit = unit; 35 | } 36 | 37 | public int getTime() { 38 | return time; 39 | } 40 | 41 | public TimeUnit getUnit() { 42 | return unit; 43 | } 44 | 45 | @DataBoundSetter 46 | public void setActivity(boolean activity) { 47 | this.activity = activity; 48 | } 49 | 50 | public boolean isActivity() { 51 | return activity; 52 | } 53 | 54 | @Override 55 | public DescriptorImpl getDescriptor() { 56 | return (DescriptorImpl) super.getDescriptor(); 57 | } 58 | 59 | @Override 60 | public StepExecution start(StepContext context) throws Exception { 61 | return new TimeoutStepExecution(this, context); 62 | } 63 | 64 | @Extension 65 | public static class DescriptorImpl extends StepDescriptor { 66 | 67 | @Override 68 | public String getFunctionName() { 69 | return "timeout"; 70 | } 71 | 72 | @Override 73 | public boolean takesImplicitBlockArgument() { 74 | return true; 75 | } 76 | 77 | @NonNull 78 | @Override 79 | public String getDisplayName() { 80 | return "Enforce time limit"; 81 | } 82 | 83 | public ListBoxModel doFillUnitItems() { 84 | ListBoxModel r = new ListBoxModel(); 85 | for (TimeUnit unit : TimeUnit.values()) { 86 | r.add(unit.name()); 87 | } 88 | return r; 89 | } 90 | 91 | @Override 92 | public Set> getRequiredContext() { 93 | return Collections.singleton(TaskListener.class); 94 | } 95 | 96 | // TODO argumentsToString as for SleepStep 97 | 98 | } 99 | 100 | private static final long serialVersionUID = 1L; 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/DeleteDirStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 Cloudbees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.FilePath; 30 | import java.util.Collections; 31 | import java.util.Set; 32 | import org.kohsuke.stapler.DataBoundConstructor; 33 | 34 | /** 35 | * Simple step that will wipe out the current working directory in a workflows workspace. 36 | */ 37 | public final class DeleteDirStep extends Step { 38 | 39 | @DataBoundConstructor 40 | public DeleteDirStep() {} 41 | 42 | @Override 43 | public StepExecution start(StepContext context) throws Exception { 44 | return new Execution(context); 45 | } 46 | 47 | @Extension 48 | public static final class DescriptorImpl extends StepDescriptor { 49 | 50 | @Override 51 | public String getFunctionName() { 52 | return "deleteDir"; 53 | } 54 | 55 | @NonNull 56 | @Override 57 | public String getDisplayName() { 58 | return "Recursively delete the current directory from the workspace"; 59 | } 60 | 61 | @Override 62 | public Set> getRequiredContext() { 63 | return Collections.singleton(FilePath.class); 64 | } 65 | } 66 | 67 | public static final class Execution extends SynchronousNonBlockingStepExecution { 68 | 69 | Execution(StepContext context) { 70 | super(context); 71 | } 72 | 73 | @Override 74 | protected Void run() throws Exception { 75 | getContext().get(FilePath.class).deleteRecursive(); 76 | return null; 77 | } 78 | 79 | private static final long serialVersionUID = 1L; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/ErrorStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.AbortException; 30 | import hudson.Extension; 31 | import java.util.Collections; 32 | import java.util.Set; 33 | import org.kohsuke.stapler.DataBoundConstructor; 34 | 35 | public final class ErrorStep extends Step { 36 | 37 | private final String message; 38 | 39 | @DataBoundConstructor 40 | public ErrorStep(String message) { 41 | this.message = message; 42 | } 43 | 44 | public String getMessage() { 45 | return message; 46 | } 47 | 48 | @Override 49 | public StepExecution start(StepContext context) throws Exception { 50 | return new Execution(message, context); 51 | } 52 | 53 | public static final class Execution extends SynchronousStepExecution { 54 | 55 | private static final long serialVersionUID = 1L; 56 | 57 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 58 | private final transient String message; 59 | 60 | Execution(String message, StepContext context) { 61 | super(context); 62 | this.message = message; 63 | } 64 | 65 | @Override 66 | protected Void run() throws Exception { 67 | throw new AbortException(message); 68 | } 69 | } 70 | 71 | @Extension 72 | public static final class DescriptorImpl extends StepDescriptor { 73 | 74 | @Override 75 | public String getFunctionName() { 76 | return "error"; 77 | } 78 | 79 | @NonNull 80 | @Override 81 | public String getDisplayName() { 82 | return "Error signal"; 83 | } 84 | 85 | @Override 86 | public Set> getRequiredContext() { 87 | return Collections.emptySet(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/CatchExecutionOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2019 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.CheckForNull; 28 | import edu.umd.cs.findbugs.annotations.NonNull; 29 | import hudson.model.Result; 30 | import java.io.Serializable; 31 | import org.jenkinsci.plugins.workflow.actions.WarningAction; 32 | 33 | public interface CatchExecutionOptions extends Serializable { 34 | /** 35 | * A message to be printed when an error is caught. 36 | * 37 | * If {@link #getStepResultOnError} (by adding a {@link WarningAction}) 38 | */ 39 | @CheckForNull 40 | String getMessage(); 41 | 42 | /** 43 | * The result that will be used for setting the build result if an error is caught. 44 | * 45 | * Return {@link Result#SUCCESS} to leave the build result unchanged. If {@link #isCatchInterruptions} 46 | * returns {@code true}, then if a {@link FlowInterruptedException} is caught, its result will be used 47 | * instead of this value. 48 | */ 49 | @NonNull 50 | Result getBuildResultOnError(); 51 | 52 | /** 53 | * The result that will be used for annotating the with {@link WarningAction}) if an error is caught. 54 | * 55 | * Return {@link Result#SUCCESS} to leave the step result unchanged. If {@link #isCatchInterruptions} 56 | * returns {@code true}, then if a {@link FlowInterruptedException} is caught, its result will be used 57 | * instead of this value. 58 | */ 59 | @NonNull 60 | Result getStepResultOnError(); 61 | 62 | /** 63 | * Whether {@link FlowInterruptedException} should be caught and handled by the step or rethrown. 64 | * 65 | * {@link FlowInterruptedException} is commonly used to control the flow of execution for things 66 | * like builds aborted by a user and builds that time out inside of {@link TimeoutStep}. It is 67 | * sometimes desirable to rethrow these kinds of exceptions rather than catching them so as to 68 | * not interfere with their intended behavior. 69 | */ 70 | boolean isCatchInterruptions(); 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStepExecution.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import hudson.FilePath; 4 | import hudson.Launcher; 5 | import hudson.Util; 6 | import hudson.model.Run; 7 | import hudson.model.TaskListener; 8 | import hudson.remoting.VirtualChannel; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import jenkins.MasterToSlaveFileCallable; 14 | import jenkins.util.BuildListenerAdapter; 15 | 16 | /** 17 | * @author Kohsuke Kawaguchi 18 | */ 19 | public class ArtifactArchiverStepExecution extends SynchronousNonBlockingStepExecution { 20 | 21 | private final transient ArtifactArchiverStep step; 22 | 23 | ArtifactArchiverStepExecution(ArtifactArchiverStep step, StepContext context) { 24 | super(context); 25 | this.step = step; 26 | } 27 | 28 | @Override 29 | protected Void run() throws Exception { 30 | FilePath ws = getContext().get(FilePath.class); 31 | ws.mkdirs(); 32 | TaskListener listener = getContext().get(TaskListener.class); 33 | if (listener != null) { 34 | listener.getLogger().println(Messages.ArtifactArchiverStepExecution_Deprecated()); 35 | } 36 | Map files = ws.act(new ListFiles(step.getIncludes(), step.getExcludes())); 37 | if (files.isEmpty()) { 38 | if (step.getExcludes() != null && !step.getExcludes().equals("")) { 39 | listener.getLogger() 40 | .println(Messages.ArtifactArchiverStepExecution_NoFilesWithExcludes( 41 | step.getIncludes(), step.getExcludes())); 42 | } else { 43 | listener.getLogger().println(Messages.ArtifactArchiverStepExecution_NoFiles(step.getIncludes())); 44 | } 45 | } else { 46 | getContext() 47 | .get(Run.class) 48 | .pickArtifactManager() 49 | .archive( 50 | ws, 51 | getContext().get(Launcher.class), 52 | new BuildListenerAdapter(getContext().get(TaskListener.class)), 53 | files); 54 | } 55 | return null; 56 | } 57 | 58 | private static final class ListFiles extends MasterToSlaveFileCallable> { 59 | private static final long serialVersionUID = 1; 60 | private final String includes, excludes; 61 | 62 | ListFiles(String includes, String excludes) { 63 | this.includes = includes; 64 | this.excludes = excludes; 65 | } 66 | 67 | @Override 68 | public Map invoke(File basedir, VirtualChannel channel) 69 | throws IOException, InterruptedException { 70 | Map r = new HashMap<>(); 71 | for (String f : Util.createFileSet(basedir, includes, excludes) 72 | .getDirectoryScanner() 73 | .getIncludedFiles()) { 74 | f = f.replace(File.separatorChar, '/'); 75 | r.put(f, f); 76 | } 77 | return r; 78 | } 79 | } 80 | 81 | private static final long serialVersionUID = 1L; 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/GetContextStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.Extension; 30 | import java.util.Collections; 31 | import java.util.Set; 32 | import org.kohsuke.stapler.DataBoundConstructor; 33 | 34 | /** 35 | * Obtains a Jenkins API object from the current context. 36 | */ 37 | public class GetContextStep extends Step { 38 | 39 | public final Class type; 40 | 41 | @DataBoundConstructor 42 | public GetContextStep(Class type) { 43 | this.type = type; 44 | } 45 | 46 | @Override 47 | public StepExecution start(StepContext context) throws Exception { 48 | return new Execution(type, context); 49 | } 50 | 51 | @Extension 52 | public static class DescriptorImpl extends StepDescriptor { 53 | 54 | @Override 55 | public String getFunctionName() { 56 | return "getContext"; 57 | } 58 | 59 | @NonNull 60 | @Override 61 | public String getDisplayName() { 62 | return "Get contextual object from internal APIs"; 63 | } 64 | 65 | @Override 66 | public boolean isAdvanced() { 67 | return true; 68 | } 69 | 70 | @Override 71 | public Set> getRequiredContext() { 72 | return Collections.emptySet(); // depends on the instance 73 | } 74 | } 75 | 76 | public static class Execution extends SynchronousStepExecution { 77 | 78 | private static final long serialVersionUID = 1; 79 | 80 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 81 | private final transient Class type; 82 | 83 | Execution(Class type, StepContext context) { 84 | super(context); 85 | this.type = type; 86 | } 87 | 88 | @Override 89 | protected Object run() throws Exception { 90 | return getContext().get(type); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/EchoStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013-2014, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.Extension; 30 | import hudson.model.TaskListener; 31 | import java.util.Collections; 32 | import java.util.Set; 33 | import org.kohsuke.stapler.DataBoundConstructor; 34 | 35 | /** 36 | * A simple echo back statement. 37 | */ 38 | public class EchoStep extends Step { 39 | 40 | private final String message; 41 | 42 | @DataBoundConstructor 43 | public EchoStep(String message) { 44 | this.message = message; 45 | } 46 | 47 | public String getMessage() { 48 | return message; 49 | } 50 | 51 | @Override 52 | public StepExecution start(StepContext context) throws Exception { 53 | return new Execution(message, context); 54 | } 55 | 56 | @Extension 57 | public static class DescriptorImpl extends StepDescriptor { 58 | 59 | @Override 60 | public String getFunctionName() { 61 | return "echo"; 62 | } 63 | 64 | @NonNull 65 | @Override 66 | public String getDisplayName() { 67 | return "Print Message"; 68 | } 69 | 70 | @Override 71 | public Set> getRequiredContext() { 72 | return Collections.singleton(TaskListener.class); 73 | } 74 | } 75 | 76 | public static class Execution extends SynchronousStepExecution { 77 | 78 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 79 | private final transient String message; 80 | 81 | Execution(String message, StepContext context) { 82 | super(context); 83 | this.message = message; 84 | } 85 | 86 | @Override 87 | protected Void run() throws Exception { 88 | getContext().get(TaskListener.class).getLogger().println(message); 89 | return null; 90 | } 91 | 92 | private static final long serialVersionUID = 1L; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/PwdStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import static org.hamcrest.MatcherAssert.assertThat; 28 | import static org.junit.jupiter.api.Assertions.assertNull; 29 | 30 | import hudson.slaves.WorkspaceList; 31 | import java.util.List; 32 | import org.hamcrest.Matchers; 33 | import org.jenkinsci.plugins.workflow.actions.ArgumentsAction; 34 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 35 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 36 | import org.jenkinsci.plugins.workflow.graphanalysis.DepthFirstScanner; 37 | import org.jenkinsci.plugins.workflow.graphanalysis.NodeStepTypePredicate; 38 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 39 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 40 | import org.junit.jupiter.api.BeforeEach; 41 | import org.junit.jupiter.api.Test; 42 | import org.jvnet.hudson.test.JenkinsRule; 43 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 44 | 45 | @WithJenkins 46 | class PwdStepTest { 47 | 48 | private JenkinsRule r; 49 | 50 | @BeforeEach 51 | void beforeEach(JenkinsRule rule) { 52 | r = rule; 53 | } 54 | 55 | @Test 56 | void basics() throws Exception { 57 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 58 | p.setDefinition(new CpsFlowDefinition("node {echo \"cwd='${pwd()}'\"}", true)); 59 | r.assertLogContains( 60 | "cwd='" + r.jenkins.getWorkspaceFor(p) + "'", r.assertBuildStatusSuccess(p.scheduleBuild2(0))); 61 | } 62 | 63 | @Test 64 | void tmp() throws Exception { 65 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 66 | p.setDefinition(new CpsFlowDefinition("node {echo \"tmp='${pwd tmp: true}'\"}", true)); 67 | WorkflowRun b = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 68 | r.assertLogContains("tmp='" + WorkspaceList.tempDir(r.jenkins.getWorkspaceFor(p)) + "'", b); 69 | List coreStepNodes = 70 | new DepthFirstScanner().filteredNodes(b.getExecution(), new NodeStepTypePredicate("pwd")); 71 | assertThat(coreStepNodes, Matchers.hasSize(1)); 72 | assertNull(ArgumentsAction.getStepArgumentsAsString(coreStepNodes.get(0))); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/EchoStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import static org.junit.jupiter.api.Assertions.*; 28 | 29 | import java.io.StringWriter; 30 | import java.util.ArrayList; 31 | import java.util.List; 32 | import java.util.regex.Matcher; 33 | import java.util.regex.Pattern; 34 | import org.jenkinsci.plugins.workflow.actions.LogAction; 35 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 36 | import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker; 37 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 38 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 39 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 40 | import org.junit.jupiter.api.BeforeEach; 41 | import org.junit.jupiter.api.Test; 42 | import org.junit.jupiter.api.extension.RegisterExtension; 43 | import org.jvnet.hudson.test.JenkinsRule; 44 | import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; 45 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 46 | 47 | @WithJenkins 48 | class EchoStepTest { 49 | 50 | @SuppressWarnings("unused") 51 | @RegisterExtension 52 | private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); 53 | 54 | private JenkinsRule r; 55 | 56 | @BeforeEach 57 | void beforeEach(JenkinsRule rule) { 58 | r = rule; 59 | } 60 | 61 | @Test 62 | void smokes() throws Exception { 63 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 64 | p.setDefinition(new CpsFlowDefinition("echo 'hello there'", true)); 65 | WorkflowRun b = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 66 | List logActions = new ArrayList<>(); 67 | for (FlowNode n : new FlowGraphWalker(b.getExecution())) { 68 | LogAction la = n.getAction(LogAction.class); 69 | if (la != null) { 70 | logActions.add(la); 71 | } 72 | } 73 | assertEquals(1, logActions.size()); 74 | StringWriter w = new StringWriter(); 75 | logActions.get(0).getLogText().writeLogTo(0, w); 76 | assertEquals("hello there", w.toString().trim()); 77 | Matcher m = Pattern.compile("hello there").matcher(JenkinsRule.getLog(b)); 78 | assertTrue(m.find(), "message printed once"); 79 | assertFalse(m.find(), "message not printed twice"); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/FileExistsStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 Bastian Echterhoelter. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.Extension; 30 | import hudson.FilePath; 31 | import hudson.model.TaskListener; 32 | import java.util.Collections; 33 | import java.util.Set; 34 | import org.apache.commons.lang3.StringUtils; 35 | import org.kohsuke.stapler.DataBoundConstructor; 36 | 37 | public final class FileExistsStep extends Step { 38 | 39 | private final String file; 40 | 41 | @DataBoundConstructor 42 | public FileExistsStep(String file) { 43 | this.file = file; 44 | } 45 | 46 | public String getFile() { 47 | return file; 48 | } 49 | 50 | @Override 51 | public StepExecution start(StepContext context) throws Exception { 52 | return new Execution(file, context); 53 | } 54 | 55 | @Extension 56 | public static final class DescriptorImpl extends StepDescriptor { 57 | 58 | @Override 59 | public String getFunctionName() { 60 | return "fileExists"; 61 | } 62 | 63 | @NonNull 64 | @Override 65 | public String getDisplayName() { 66 | return "Verify if file exists in workspace"; 67 | } 68 | 69 | @Override 70 | public Set> getRequiredContext() { 71 | return Collections.singleton(FilePath.class); 72 | } 73 | } 74 | 75 | public static final class Execution extends SynchronousNonBlockingStepExecution { 76 | 77 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 78 | private final transient String file; 79 | 80 | Execution(String file, StepContext context) { 81 | super(context); 82 | this.file = file; 83 | } 84 | 85 | @Override 86 | protected Boolean run() throws Exception { 87 | if (StringUtils.isEmpty(file)) { 88 | getContext().get(TaskListener.class).getLogger().println(Messages.FileExistsStep_EmptyString()); 89 | return getContext().get(FilePath.class).child("").exists(); 90 | } 91 | return getContext().get(FilePath.class).child(file).exists(); 92 | } 93 | 94 | private static final long serialVersionUID = 1L; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/ArtifactUnarchiverStepExecution.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import hudson.AbortException; 5 | import hudson.FilePath; 6 | import hudson.model.Run; 7 | import hudson.model.TaskListener; 8 | import io.jenkins.plugins.httpclient.RobustHTTPClient; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.net.URL; 12 | import java.util.ArrayList; 13 | import java.util.Collection; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Map.Entry; 17 | import jenkins.model.ArtifactManager; 18 | import jenkins.util.VirtualFile; 19 | 20 | public class ArtifactUnarchiverStepExecution extends SynchronousNonBlockingStepExecution> { 21 | 22 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 23 | private final transient Map mapping; 24 | 25 | ArtifactUnarchiverStepExecution(Map mapping, StepContext context) throws Exception { 26 | super(context); 27 | if (mapping == null) { 28 | throw new AbortException("'mapping' has not been defined for this 'unarchive' step"); 29 | } 30 | this.mapping = mapping; 31 | } 32 | 33 | @Override 34 | protected List run() throws Exception { 35 | // where to copy artifacts from? 36 | Run r = getContext().get(Run.class); // TODO consider an option to override this (but in what format?) 37 | TaskListener listener = getContext().get(TaskListener.class); 38 | 39 | ArtifactManager am = r.getArtifactManager(); 40 | 41 | List files = new ArrayList<>(); 42 | 43 | for (Entry e : mapping.entrySet()) { 44 | FilePath dst = new FilePath(getContext().get(FilePath.class), e.getValue()); 45 | String src = e.getKey(); 46 | Collection all = am.root().list(src.replace('\\', '/'), null, true); 47 | if (all.isEmpty()) { 48 | throw new AbortException("no artifacts to unarchive in " + src); 49 | } else if (all.size() == 1 && all.stream().findFirst().get().equals(src)) { 50 | final String firstElement = all.stream().findFirst().get(); 51 | // the source is a file 52 | if (dst.isDirectory()) { 53 | dst = dst.child(getFileName(firstElement)); 54 | } 55 | 56 | files.add(copy(am.root().child(firstElement), dst, listener)); 57 | } else { 58 | // copy into a directory 59 | for (String path : all) { 60 | files.add(copy(am.root().child(path), dst.child(path), listener)); 61 | } 62 | } 63 | } 64 | 65 | return files; 66 | } 67 | 68 | private FilePath copy(VirtualFile src, FilePath dst, TaskListener listener) 69 | throws IOException, InterruptedException { 70 | URL u = src.toExternalURL(); 71 | if (u != null) { 72 | new RobustHTTPClient().copyFromRemotely(dst, u, listener); 73 | } else { 74 | try (InputStream in = src.open()) { 75 | dst.copyFrom(in); 76 | } 77 | } 78 | return dst; 79 | } 80 | 81 | /** 82 | * Grabs the file name portion out of a path name. 83 | */ 84 | private String getFileName(String s) { 85 | int idx = s.lastIndexOf('/'); 86 | if (idx >= 0) s = s.substring(idx + 1); 87 | idx = s.lastIndexOf('\\'); 88 | if (idx >= 0) s = s.substring(idx + 1); 89 | return s; 90 | } 91 | 92 | private static final long serialVersionUID = 1L; 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/SleepStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | 29 | import java.util.List; 30 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 31 | import org.jenkinsci.plugins.workflow.cps.CpsFlowExecution; 32 | import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode; 33 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 34 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 35 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 36 | import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; 37 | import org.junit.jupiter.api.Test; 38 | import org.junit.jupiter.api.extension.RegisterExtension; 39 | import org.jvnet.hudson.test.Issue; 40 | import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; 41 | import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension; 42 | 43 | class SleepStepTest { 44 | 45 | @SuppressWarnings("unused") 46 | @RegisterExtension 47 | private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); 48 | 49 | @RegisterExtension 50 | private final JenkinsSessionExtension sessions = new JenkinsSessionExtension(); 51 | 52 | @Test 53 | void sleepAndRestart() throws Throwable { 54 | sessions.then(j -> { 55 | WorkflowJob p = j.createProject(WorkflowJob.class, "p"); 56 | p.setDefinition(new CpsFlowDefinition("semaphore 'start'; sleep 10", true)); 57 | WorkflowRun b = p.scheduleBuild2(0).waitForStart(); 58 | SemaphoreStep.waitForStart("start/1", b); 59 | SemaphoreStep.success("start/1", null); 60 | ((CpsFlowExecution) b.getExecution()).waitForSuspension(); 61 | List heads = b.getExecution().getCurrentHeads(); 62 | assertEquals(1, heads.size()); 63 | assertEquals( 64 | j.jenkins.getDescriptorByType(SleepStep.DescriptorImpl.class), 65 | ((StepAtomNode) heads.get(0)).getDescriptor()); 66 | }); 67 | sessions.then(j -> { 68 | WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); 69 | WorkflowRun b = p.getLastBuild(); 70 | j.assertBuildStatusSuccess(j.waitForCompletion(b)); 71 | }); 72 | } 73 | 74 | @Issue("JENKINS-31701") 75 | @Test 76 | void sleepInsideNode() throws Throwable { 77 | sessions.then(j -> { 78 | WorkflowJob p = j.createProject(WorkflowJob.class, "p"); 79 | p.setDefinition(new CpsFlowDefinition("node {sleep 1}", true)); 80 | j.buildAndAssertSuccess(p); 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013-2014, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.model.TaskListener; 30 | import hudson.util.FormValidation; 31 | import java.util.Collections; 32 | import java.util.List; 33 | import java.util.Set; 34 | import org.jenkinsci.plugins.workflow.flow.ErrorCondition; 35 | import org.kohsuke.stapler.DataBoundConstructor; 36 | import org.kohsuke.stapler.DataBoundSetter; 37 | import org.kohsuke.stapler.QueryParameter; 38 | 39 | /** 40 | * Executes the body up to N times. 41 | * 42 | * @author Kohsuke Kawaguchi 43 | */ 44 | public class RetryStep extends Step { 45 | 46 | private final int count; 47 | private List conditions; 48 | 49 | @DataBoundConstructor 50 | public RetryStep(int count) { 51 | this.count = count; 52 | } 53 | 54 | public int getCount() { 55 | return count; 56 | } 57 | 58 | public List getConditions() { 59 | return conditions; 60 | } 61 | 62 | @DataBoundSetter 63 | public void setConditions(List conditions) { 64 | this.conditions = conditions; 65 | } 66 | 67 | @Override 68 | public DescriptorImpl getDescriptor() { 69 | return (DescriptorImpl) super.getDescriptor(); 70 | } 71 | 72 | @Override 73 | public StepExecution start(StepContext context) throws Exception { 74 | return new RetryStepExecution(count, context, conditions); 75 | } 76 | 77 | @Extension 78 | public static class DescriptorImpl extends StepDescriptor { 79 | 80 | @Override 81 | public String getFunctionName() { 82 | return "retry"; 83 | } 84 | 85 | @Override 86 | public boolean takesImplicitBlockArgument() { 87 | return true; 88 | } 89 | 90 | @NonNull 91 | @Override 92 | public String getDisplayName() { 93 | return "Retry the body up to N times"; 94 | } 95 | 96 | @Override 97 | public Set> getRequiredContext() { 98 | return Collections.singleton(TaskListener.class); 99 | } 100 | 101 | public FormValidation doCheckCount(@QueryParameter int count) { 102 | if (count < 1) { 103 | return FormValidation.error("Count must be positive."); 104 | } else if (count == 1) { 105 | return FormValidation.warning("Count of one means that the retry step has no effect. Use ≥2."); 106 | } else { 107 | return FormValidation.ok(); 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/UnstableStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2019 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import static org.hamcrest.MatcherAssert.assertThat; 28 | import static org.hamcrest.Matchers.equalTo; 29 | import static org.hamcrest.Matchers.notNullValue; 30 | 31 | import hudson.model.Result; 32 | import org.jenkinsci.plugins.workflow.actions.WarningAction; 33 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 34 | import org.jenkinsci.plugins.workflow.flow.FlowExecution; 35 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 36 | import org.jenkinsci.plugins.workflow.graphanalysis.DepthFirstScanner; 37 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 38 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 39 | import org.junit.jupiter.api.BeforeEach; 40 | import org.junit.jupiter.api.Test; 41 | import org.junit.jupiter.api.extension.RegisterExtension; 42 | import org.jvnet.hudson.test.Issue; 43 | import org.jvnet.hudson.test.JenkinsRule; 44 | import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; 45 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 46 | 47 | @Issue("JENKINS-45579") 48 | @WithJenkins 49 | class UnstableStepTest { 50 | 51 | @SuppressWarnings("unused") 52 | @RegisterExtension 53 | private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); 54 | 55 | private JenkinsRule r; 56 | 57 | @BeforeEach 58 | void beforeEach(JenkinsRule rule) { 59 | r = rule; 60 | } 61 | 62 | @Test 63 | void smokes() throws Exception { 64 | WorkflowJob p = r.createProject(WorkflowJob.class); 65 | p.setDefinition(new CpsFlowDefinition("unstable('oops')", true)); 66 | WorkflowRun b = r.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0)); 67 | assertWarning(b, "oops"); 68 | } 69 | 70 | @Test 71 | void messageRequired() throws Exception { 72 | WorkflowJob p = r.createProject(WorkflowJob.class); 73 | p.setDefinition(new CpsFlowDefinition("unstable()", true)); 74 | WorkflowRun b = r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)); 75 | r.assertLogContains("A non-empty message is required", b); 76 | } 77 | 78 | private void assertWarning(WorkflowRun run, String expectedMessage) throws Exception { 79 | r.assertLogContains("WARNING: " + expectedMessage, run); 80 | FlowExecution exec = run.getExecution(); 81 | FlowNode warningNode = new DepthFirstScanner() 82 | .findFirstMatch(exec, node -> node.getPersistentAction(WarningAction.class) != null); 83 | assertThat(warningNode, notNullValue()); 84 | WarningAction warning = warningNode.getPersistentAction(WarningAction.class); 85 | assertThat(warning, notNullValue()); 86 | assertThat(warning.getMessage(), equalTo(expectedMessage)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/PwdStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.Extension; 30 | import hudson.FilePath; 31 | import hudson.slaves.WorkspaceList; 32 | import java.io.IOException; 33 | import java.util.Collections; 34 | import java.util.Map; 35 | import java.util.Objects; 36 | import java.util.Set; 37 | import org.kohsuke.stapler.DataBoundConstructor; 38 | import org.kohsuke.stapler.DataBoundSetter; 39 | 40 | /** 41 | * Returns the working directory path. 42 | * 43 | * Used like: 44 | * 45 | *
 46 |  * node {
 47 |  *     def x = pwd() // where is my workspace?
 48 |  * }
 49 |  * 
50 | */ 51 | public class PwdStep extends Step { 52 | 53 | private boolean tmp; 54 | 55 | @DataBoundConstructor 56 | public PwdStep() {} 57 | 58 | public boolean isTmp() { 59 | return tmp; 60 | } 61 | 62 | @DataBoundSetter 63 | public void setTmp(boolean tmp) { 64 | this.tmp = tmp; 65 | } 66 | 67 | @Override 68 | public StepExecution start(StepContext context) throws Exception { 69 | return new Execution(tmp, context); 70 | } 71 | 72 | @Extension 73 | public static final class DescriptorImpl extends StepDescriptor { 74 | 75 | @Override 76 | public String getFunctionName() { 77 | return "pwd"; 78 | } 79 | 80 | @NonNull 81 | @Override 82 | public String getDisplayName() { 83 | return "Determine current directory"; 84 | } 85 | 86 | @Override 87 | public Set> getRequiredContext() { 88 | return Collections.singleton(FilePath.class); 89 | } 90 | 91 | @Override 92 | public String argumentsToString(@NonNull Map namedArgs) { 93 | return null; // "true" is not a reasonable description 94 | } 95 | } 96 | 97 | public static class Execution extends SynchronousStepExecution { 98 | 99 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 100 | private final transient boolean tmp; 101 | 102 | Execution(boolean tmp, StepContext context) { 103 | super(context); 104 | this.tmp = tmp; 105 | } 106 | 107 | @Override 108 | protected String run() throws Exception { 109 | FilePath cwd = getContext().get(FilePath.class); 110 | Objects.requireNonNull(cwd); 111 | if (tmp) { 112 | cwd = WorkspaceList.tempDir(cwd); 113 | if (cwd == null) { 114 | throw new IOException("Failed to set up a temporary directory."); 115 | } 116 | } 117 | return cwd.getRemote(); 118 | } 119 | 120 | private static final long serialVersionUID = 1L; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import edu.umd.cs.findbugs.annotations.CheckForNull; 4 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 5 | import hudson.AbortException; 6 | import hudson.Functions; 7 | import hudson.model.Run; 8 | import hudson.model.TaskListener; 9 | import java.io.IOException; 10 | import java.util.List; 11 | import org.jenkinsci.plugins.workflow.flow.ErrorCondition; 12 | 13 | /** 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | public class RetryStepExecution extends AbstractStepExecutionImpl { 17 | 18 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 19 | private final transient int count; 20 | 21 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 22 | private final transient @CheckForNull List conditions; 23 | 24 | RetryStepExecution(int count, StepContext context, List conditions) { 25 | super(context); 26 | this.count = count; 27 | this.conditions = conditions; 28 | } 29 | 30 | @Override 31 | public boolean start() throws Exception { 32 | StepContext context = getContext(); 33 | context.newBodyInvoker().withCallback(new Callback(count, conditions)).start(); 34 | return false; // execution is asynchronous 35 | } 36 | 37 | @Override 38 | public void onResume() {} 39 | 40 | private static class Callback extends BodyExecutionCallback { 41 | 42 | private int left; 43 | private final @CheckForNull List conditions; 44 | 45 | Callback(int count, List conditions) { 46 | left = count; 47 | this.conditions = conditions; 48 | } 49 | 50 | /* Could be added, but seems unnecessary, given the message already printed in onFailure: 51 | @Override public void onStart(StepContext context) { 52 | try { 53 | context.get(TaskListener.class).getLogger().println(left + " tries left"); 54 | } catch (Exception x) { 55 | context.onFailure(x); 56 | } 57 | } 58 | */ 59 | 60 | @Override 61 | public void onSuccess(StepContext context, Object result) { 62 | context.onSuccess(result); 63 | } 64 | 65 | @Override 66 | public void onFailure(StepContext context, Throwable t) { 67 | try { 68 | left--; 69 | TaskListener l = context.get(TaskListener.class); 70 | if (left > 0 && matchesConditions(t, context)) { 71 | if (t instanceof AbortException) { 72 | l.error(t.getMessage()); 73 | } else if (t instanceof FlowInterruptedException) { 74 | FlowInterruptedException fie = (FlowInterruptedException) t; 75 | fie.handle(context.get(Run.class), l); 76 | } else { 77 | Functions.printStackTrace(t, l.error("Execution failed")); 78 | } 79 | l.getLogger().println("Retrying"); 80 | context.newBodyInvoker().withCallback(this).start(); 81 | } else { 82 | // No need to print anything in this case, since it will be thrown up anyway. 83 | context.onFailure(t); 84 | } 85 | } catch (Throwable p) { 86 | context.onFailure(p); 87 | } 88 | } 89 | 90 | private boolean matchesConditions(Throwable t, StepContext context) throws IOException, InterruptedException { 91 | if (conditions == null || conditions.isEmpty()) { 92 | return !(t instanceof FlowInterruptedException) 93 | || !((FlowInterruptedException) t).isActualInterruption(); 94 | } 95 | for (ErrorCondition ec : conditions) { 96 | if (ec.test(t, context)) { 97 | return true; 98 | } 99 | } 100 | return false; 101 | } 102 | 103 | private static final long serialVersionUID = 1L; 104 | } 105 | 106 | private static final long serialVersionUID = 1L; 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/UnstableStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2019 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.Util; 30 | import hudson.model.Result; 31 | import hudson.model.Run; 32 | import hudson.model.TaskListener; 33 | import hudson.util.FormValidation; 34 | import java.util.Collections; 35 | import java.util.HashSet; 36 | import java.util.Set; 37 | import org.jenkinsci.plugins.workflow.actions.WarningAction; 38 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 39 | import org.kohsuke.stapler.DataBoundConstructor; 40 | import org.kohsuke.stapler.QueryParameter; 41 | 42 | public class UnstableStep extends Step { 43 | 44 | private final String message; 45 | 46 | @DataBoundConstructor 47 | public UnstableStep(String message) { 48 | message = Util.fixEmptyAndTrim(message); 49 | if (message == null) { 50 | throw new IllegalArgumentException("A non-empty message is required"); 51 | } 52 | this.message = message; 53 | } 54 | 55 | public String getMessage() { 56 | return message; 57 | } 58 | 59 | @Override 60 | public StepExecution start(StepContext context) throws Exception { 61 | return new UnstableStepExecution(this, context); 62 | } 63 | 64 | private static class UnstableStepExecution extends SynchronousStepExecution { 65 | private static final long serialVersionUID = 1L; 66 | private final transient UnstableStep step; 67 | 68 | private UnstableStepExecution(UnstableStep step, StepContext context) { 69 | super(context); 70 | this.step = step; 71 | } 72 | 73 | @Override 74 | protected Void run() throws Exception { 75 | getContext() 76 | .get(FlowNode.class) 77 | .addOrReplaceAction(new WarningAction(Result.UNSTABLE).withMessage(step.message)); 78 | getContext().get(Run.class).setResult(Result.UNSTABLE); 79 | getContext().get(TaskListener.class).getLogger().append("WARNING: ").println(step.message); 80 | return null; 81 | } 82 | } 83 | 84 | @Extension 85 | public static class DescriptorImpl extends StepDescriptor { 86 | @Override 87 | public String getFunctionName() { 88 | return "unstable"; 89 | } 90 | 91 | @NonNull 92 | @Override 93 | public String getDisplayName() { 94 | return "Set stage result to unstable"; 95 | } 96 | 97 | @Override 98 | public Set> getRequiredContext() { 99 | Set> context = new HashSet<>(); 100 | Collections.addAll(context, FlowNode.class, Run.class, TaskListener.class); 101 | return Collections.unmodifiableSet(context); 102 | } 103 | 104 | public FormValidation doCheckMessage(@QueryParameter String message) { 105 | if (Util.fixEmptyAndTrim(message) == null) { 106 | return FormValidation.error("Message must be non-empty"); 107 | } 108 | return FormValidation.ok(); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/support/steps/stash/UnstashStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.support.steps.stash; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.EnvVars; 30 | import hudson.Extension; 31 | import hudson.FilePath; 32 | import hudson.Launcher; 33 | import hudson.model.Run; 34 | import hudson.model.TaskListener; 35 | import java.util.Collections; 36 | import java.util.HashSet; 37 | import java.util.Set; 38 | import jenkins.model.Jenkins; 39 | import org.jenkinsci.plugins.workflow.flow.StashManager; 40 | import org.jenkinsci.plugins.workflow.steps.Step; 41 | import org.jenkinsci.plugins.workflow.steps.StepContext; 42 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor; 43 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 44 | import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; 45 | import org.kohsuke.stapler.DataBoundConstructor; 46 | 47 | public class UnstashStep extends Step { 48 | 49 | private final @NonNull String name; 50 | 51 | @DataBoundConstructor 52 | public UnstashStep(@NonNull String name) { 53 | Jenkins.checkGoodName(name); 54 | this.name = name; 55 | } 56 | 57 | @NonNull 58 | public String getName() { 59 | return name; 60 | } 61 | 62 | @Override 63 | public StepExecution start(StepContext context) throws Exception { 64 | return new Execution(name, context); 65 | } 66 | 67 | public static class Execution extends SynchronousNonBlockingStepExecution { 68 | 69 | private static final long serialVersionUID = 1L; 70 | 71 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 72 | private final transient String name; 73 | 74 | Execution(String name, StepContext context) { 75 | super(context); 76 | this.name = name; 77 | } 78 | 79 | @Override 80 | protected Void run() throws Exception { 81 | StashManager.unstash( 82 | getContext().get(Run.class), 83 | name, 84 | getContext().get(FilePath.class), 85 | getContext().get(Launcher.class), 86 | getContext().get(EnvVars.class), 87 | getContext().get(TaskListener.class)); 88 | return null; 89 | } 90 | } 91 | 92 | @Extension 93 | public static class DescriptorImpl extends StepDescriptor { 94 | 95 | @Override 96 | public String getFunctionName() { 97 | return "unstash"; 98 | } 99 | 100 | @NonNull 101 | @Override 102 | public String getDisplayName() { 103 | return "Restore files previously stashed"; 104 | } 105 | 106 | @Override 107 | public Set> getRequiredContext() { 108 | Set> context = new HashSet<>(); 109 | Collections.addAll(context, Run.class, FilePath.class, Launcher.class, EnvVars.class, TaskListener.class); 110 | return Collections.unmodifiableSet(context); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/WithContextStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 29 | import hudson.Extension; 30 | import hudson.LauncherDecorator; 31 | import hudson.console.ConsoleLogFilter; 32 | import java.util.Collections; 33 | import java.util.Set; 34 | import org.kohsuke.stapler.DataBoundConstructor; 35 | 36 | /** 37 | * Supplies a contextual Jenkins API object to a block. 38 | */ 39 | public class WithContextStep extends Step { 40 | 41 | public final Object context; 42 | 43 | @DataBoundConstructor 44 | public WithContextStep(Object context) { 45 | this.context = context; 46 | } 47 | 48 | @Override 49 | public StepExecution start(StepContext context) throws Exception { 50 | return new Execution(this.context, context); 51 | } 52 | 53 | @Extension 54 | public static class DescriptorImpl extends StepDescriptor { 55 | 56 | @Override 57 | public String getFunctionName() { 58 | return "withContext"; 59 | } 60 | 61 | @Override 62 | public boolean takesImplicitBlockArgument() { 63 | return true; 64 | } 65 | 66 | @NonNull 67 | @Override 68 | public String getDisplayName() { 69 | return "Use contextual object from internal APIs within a block"; 70 | } 71 | 72 | @Override 73 | public boolean isAdvanced() { 74 | return true; 75 | } 76 | 77 | @Override 78 | public Set> getRequiredContext() { 79 | return Collections.emptySet(); 80 | } 81 | } 82 | 83 | public static class Execution extends AbstractStepExecutionImpl { 84 | 85 | private static final long serialVersionUID = 1; 86 | 87 | @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") 88 | private transient Object obj; 89 | 90 | Execution(Object obj, StepContext context) { 91 | super(context); 92 | this.obj = obj; 93 | } 94 | 95 | @Override 96 | public boolean start() throws Exception { 97 | StepContext context = getContext(); 98 | if (obj instanceof ConsoleLogFilter) { 99 | obj = BodyInvoker.mergeConsoleLogFilters(context.get(ConsoleLogFilter.class), (ConsoleLogFilter) obj); 100 | } else if (obj instanceof LauncherDecorator) { 101 | obj = BodyInvoker.mergeLauncherDecorators( 102 | context.get(LauncherDecorator.class), (LauncherDecorator) obj); 103 | } else if (obj instanceof EnvironmentExpander) { 104 | obj = EnvironmentExpander.merge(context.get(EnvironmentExpander.class), (EnvironmentExpander) obj); 105 | } 106 | context.newBodyInvoker() 107 | .withContext(obj) 108 | .withCallback(BodyExecutionCallback.wrap(context)) 109 | .start(); 110 | return false; 111 | } 112 | 113 | @Override 114 | public void onResume() {} 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/WriteFileStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.FilePath; 30 | import hudson.Util; 31 | import java.io.OutputStream; 32 | import java.util.Base64; 33 | import java.util.Collections; 34 | import java.util.Map; 35 | import java.util.Set; 36 | import org.kohsuke.stapler.DataBoundConstructor; 37 | import org.kohsuke.stapler.DataBoundSetter; 38 | 39 | public final class WriteFileStep extends Step { 40 | 41 | private final String file; 42 | private final String text; 43 | private String encoding; 44 | 45 | @DataBoundConstructor 46 | public WriteFileStep(String file, String text) { 47 | this.file = file; 48 | this.text = text; 49 | } 50 | 51 | public String getFile() { 52 | return file; 53 | } 54 | 55 | public String getText() { 56 | return text; 57 | } 58 | 59 | public String getEncoding() { 60 | return encoding; 61 | } 62 | 63 | /** 64 | * Set the encoding to be used when writing the file. If the specified value is null or 65 | * whitespace-only, then the platform default encoding will be used. If the text is a 66 | * Base64-encoded string, the decoded binary data can be written to the file by specifying 67 | * {@code Base64} as the encoding. 68 | */ 69 | @DataBoundSetter 70 | public void setEncoding(String encoding) { 71 | this.encoding = Util.fixEmptyAndTrim(encoding); 72 | } 73 | 74 | @Override 75 | public StepExecution start(StepContext context) throws Exception { 76 | return new Execution(this, context); 77 | } 78 | 79 | @Extension 80 | public static final class DescriptorImpl extends StepDescriptor { 81 | 82 | @Override 83 | public String getFunctionName() { 84 | return "writeFile"; 85 | } 86 | 87 | @NonNull 88 | @Override 89 | public String getDisplayName() { 90 | return "Write file to workspace"; 91 | } 92 | 93 | @Override 94 | public Set> getRequiredContext() { 95 | return Collections.singleton(FilePath.class); 96 | } 97 | 98 | @Override 99 | public String argumentsToString(Map namedArgs) { 100 | Object file = namedArgs.get("file"); 101 | return file instanceof String ? (String) file : null; 102 | } 103 | } 104 | 105 | public static final class Execution extends SynchronousNonBlockingStepExecution { 106 | 107 | private final transient WriteFileStep step; 108 | 109 | Execution(WriteFileStep step, StepContext context) { 110 | super(context); 111 | this.step = step; 112 | } 113 | 114 | @Override 115 | protected Void run() throws Exception { 116 | FilePath file = getContext().get(FilePath.class).child(step.file); 117 | if (ReadFileStep.BASE64_ENCODING.equals(step.encoding)) { 118 | try (OutputStream os = file.write()) { 119 | os.write(Base64.getDecoder().decode(step.text)); 120 | } 121 | } else { 122 | file.write(step.text, step.encoding); // The platform default is used if encoding is null. 123 | } 124 | return null; 125 | } 126 | 127 | private static final long serialVersionUID = 1L; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/WarnErrorStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2019 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.Util; 30 | import hudson.model.Result; 31 | import hudson.model.Run; 32 | import hudson.model.TaskListener; 33 | import hudson.util.FormValidation; 34 | import java.util.Collections; 35 | import java.util.HashSet; 36 | import java.util.Set; 37 | import org.jenkinsci.plugins.workflow.actions.WarningAction; 38 | import org.jenkinsci.plugins.workflow.graph.FlowNode; 39 | import org.kohsuke.stapler.DataBoundConstructor; 40 | import org.kohsuke.stapler.DataBoundSetter; 41 | import org.kohsuke.stapler.QueryParameter; 42 | 43 | /** 44 | * Runs a block, and if that block fails, prints a message, marks the build as {@link Result#UNSTABLE}, adds a 45 | * {@link WarningAction} to the step, and then continues execution normally. 46 | * 47 | * @see CatchErrorStep 48 | */ 49 | public class WarnErrorStep extends Step implements CatchExecutionOptions { 50 | private static final long serialVersionUID = 1L; 51 | 52 | private final String message; 53 | private boolean catchInterruptions = true; 54 | 55 | @DataBoundConstructor 56 | public WarnErrorStep(String message) { 57 | message = Util.fixEmptyAndTrim(message); 58 | if (message == null) { 59 | throw new IllegalArgumentException("A non-empty message is required"); 60 | } 61 | this.message = message; 62 | } 63 | 64 | @Override 65 | public String getMessage() { 66 | return message; 67 | } 68 | 69 | @NonNull 70 | @Override 71 | public Result getBuildResultOnError() { 72 | return Result.UNSTABLE; 73 | } 74 | 75 | @NonNull 76 | @Override 77 | public Result getStepResultOnError() { 78 | return Result.UNSTABLE; 79 | } 80 | 81 | @Override 82 | public boolean isCatchInterruptions() { 83 | return catchInterruptions; 84 | } 85 | 86 | @DataBoundSetter 87 | public void setCatchInterruptions(boolean catchInterruptions) { 88 | this.catchInterruptions = catchInterruptions; 89 | } 90 | 91 | @Override 92 | public StepExecution start(StepContext context) throws Exception { 93 | return new CatchErrorStep.Execution(context, this); 94 | } 95 | 96 | @Extension 97 | public static class DescriptorImpl extends StepDescriptor { 98 | @Override 99 | public String getFunctionName() { 100 | return "warnError"; 101 | } 102 | 103 | @NonNull 104 | @Override 105 | public String getDisplayName() { 106 | return "Catch error and set build and stage result to unstable"; 107 | } 108 | 109 | @Override 110 | public boolean takesImplicitBlockArgument() { 111 | return true; 112 | } 113 | 114 | @Override 115 | public Set> getRequiredContext() { 116 | Set> context = new HashSet<>(); 117 | Collections.addAll(context, FlowNode.class, Run.class, TaskListener.class); 118 | return Collections.unmodifiableSet(context); 119 | } 120 | 121 | public FormValidation doCheckMessage(@QueryParameter String message) { 122 | if (Util.fixEmptyAndTrim(message) == null) { 123 | return FormValidation.error("Message must be non-empty"); 124 | } 125 | return FormValidation.ok(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /CORE-STEPS.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Many Jenkins plugins add builders or post-build actions (collectively, _build steps_) for use in freestyle and similar projects. 4 | (Jenkins core also adds a few of these, though most have been split off into their own plugins or could be split off.) 5 | 6 | In many cases these build steps would be valuable to use from Pipelines, but it would be overkill to define a separate Pipeline-only step. 7 | Therefore selected build steps can be called directly from Pipelines. 8 | 9 | # Syntax 10 | 11 | As an example, you can write a Pipeline script: 12 | 13 | ```groovy 14 | node { 15 | sh 'make something' 16 | step([$class: 'ArtifactArchiver', artifacts: 'something']) 17 | } 18 | ``` 19 | 20 | Here we are running the standard _Archive the artifacts_ post-build action (`hudson.tasks.ArtifactArchiver`), 21 | and configuring the _Files to archive_ property (`artifacts`) to archive our file `something` produced in an earlier step. 22 | The easiest way to see what class and field names to use is to use the _Snippet Generator_ feature in the Pipeline configuration page. 23 | 24 | See the [compatibility list](https://github.com/jenkinsci/pipeline-plugin/blob/master/COMPATIBILITY.md#build-steps-and-post-build-actions) for the list of currently supported steps. 25 | 26 | ## Simplified syntax 27 | 28 | Build steps and post-build actions in Jenkins core as of 2.2, 29 | and in some plugins according to their individual changelogs, 30 | have defined symbols which allow for a more concise syntax. 31 | _Snippet Generator_ will offer this when available. 32 | For example, the above script may also be written: 33 | 34 | ```groovy 35 | node { 36 | sh 'make something' 37 | archiveArtifacts 'something' 38 | } 39 | ``` 40 | 41 | # Interacting with build status 42 | 43 | Builders generally have a simple mode of operation: they run, and either pass or fail. 44 | So you can call these at any point in your pipeline. 45 | 46 | Post-build actions (also known as _publishers_) are divided into two classes: 47 | 48 | * _Recorders_ like the JUnit publisher add something to the build, and might affect its status. 49 | * _Notifiers_ like the mailer cannot affect the build’s status, though they may behave differently depending on its status. 50 | 51 | When a recorder is run from a pipeline, it might set the build’s status (for example to unstable), but otherwise is likely to work intuitively. 52 | Running a notifier is trickier since normally a pipeline in progress has no status yet, unlike a freestyle project whose status is determined before the notifier is called. 53 | To help interoperate better with these, you can use the `catchError` step, or manually set a build status using `currentBuild.result`. 54 | See the [help for the `catchError` step](src/main/resources/org/jenkinsci/plugins/workflow/steps/CatchErrorStep/help.html) for examples. 55 | 56 | ## Plain catch blocks 57 | 58 | Some important publishers also have dedicated Pipeline steps, so that you can use a more flexible idiom. 59 | For example, `mail` lets you unconditionally send mail of your choice: 60 | 61 | ```groovy 62 | node { 63 | try { 64 | sh 'might fail' 65 | mail subject: 'all well', to: 'admin@somewhere', body: 'All well.' 66 | } catch (e) { 67 | def w = new StringWriter() 68 | e.printStackTrace(new PrintWriter(w)) 69 | mail subject: "failed with ${e.message}", to: 'admin@somewhere', body: "Failed: ${w}" 70 | throw e 71 | } 72 | } 73 | ``` 74 | 75 | though this would not automatically adjust the message according to the status of _previous_ builds as the standard mail notifier does. 76 | For that, check if `currentBuild.previousBuild` exists, what its `.result` is, etc. 77 | 78 | The Pipeline Model Definition plugin (“Declarative Pipeline”) has a built-in construct for running selected publishers under certain conditions. 79 | 80 | # Build wrappers 81 | 82 | The `wrap` step may be used to run a build wrapper defined originally for freestyle projects. 83 | In a Pipeline, any block of code (inside `node`) may be wrapped in this way, not necessarily the whole build. 84 | 85 | For example, the Xvnc plugin allows a headless build server to run GUI tests by allocating an in-memory-only X11 display. 86 | To use this plugin from a Pipeline, assuming a version with the appropriate update: 87 | 88 | ```groovy 89 | node('linux') { 90 | wrap([$class: 'Xvnc', useXauthority: true]) { 91 | // here $DISPLAY is set to :11 or similar, and $XAUTHORITY too 92 | sh 'make selenium-tests' // or whatever 93 | } 94 | // now the display is torn down and the environment variables gone 95 | } 96 | ``` 97 | 98 | # Adding support from plugins 99 | 100 | See the [compatibility guide](https://github.com/jenkinsci/pipeline-plugin/blob/master/DEVGUIDE.md#build-steps). 101 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/ReadFileStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.FilePath; 30 | import hudson.Util; 31 | import java.io.InputStream; 32 | import java.util.Base64; 33 | import java.util.Collections; 34 | import java.util.Set; 35 | import org.apache.commons.io.IOUtils; 36 | import org.kohsuke.stapler.DataBoundConstructor; 37 | import org.kohsuke.stapler.DataBoundSetter; 38 | 39 | public final class ReadFileStep extends Step { 40 | 41 | /*package*/ static final String BASE64_ENCODING = "Base64"; 42 | 43 | private final String file; 44 | private String encoding; 45 | 46 | @DataBoundConstructor 47 | public ReadFileStep(String file) { 48 | // Normally pointless to verify that this is a relative path, 49 | // since shell steps can anyway read and write files anywhere on the agent. 50 | // Could be necessary in case a plugin installs a {@link LauncherDecorator} 51 | // which keeps commands inside some kind of jail. 52 | // In that case we would need some API to determine that such a jail is in effect 53 | // and this validation must be enforced. 54 | // But just checking the path is anyway not sufficient (due to crafted symlinks); 55 | // would need to check the final resulting path. 56 | // Same for WriteFileStep, PushdStep, FileExistsStep. 57 | this.file = file; 58 | } 59 | 60 | public String getFile() { 61 | return file; 62 | } 63 | 64 | public String getEncoding() { 65 | return encoding; 66 | } 67 | 68 | /** 69 | * Set the encoding to be used when reading the file. If the specified value is null or 70 | * whitespace-only, then the platform default encoding will be used. Binary resources can be 71 | * loaded as a Base64-encoded string by specifying {@code Base64} as the encoding. 72 | */ 73 | @DataBoundSetter 74 | public void setEncoding(String encoding) { 75 | this.encoding = Util.fixEmptyAndTrim(encoding); 76 | } 77 | 78 | @Override 79 | public StepExecution start(StepContext context) throws Exception { 80 | return new Execution(this, context); 81 | } 82 | 83 | @Extension 84 | public static final class DescriptorImpl extends StepDescriptor { 85 | 86 | @Override 87 | public String getFunctionName() { 88 | return "readFile"; 89 | } 90 | 91 | @NonNull 92 | @Override 93 | public String getDisplayName() { 94 | return "Read file from workspace"; 95 | } 96 | 97 | @Override 98 | public Set> getRequiredContext() { 99 | return Collections.singleton(FilePath.class); 100 | } 101 | } 102 | 103 | public static final class Execution extends SynchronousNonBlockingStepExecution { 104 | 105 | private final transient ReadFileStep step; 106 | 107 | Execution(ReadFileStep step, StepContext context) { 108 | super(context); 109 | this.step = step; 110 | } 111 | 112 | @Override 113 | protected String run() throws Exception { 114 | try (InputStream is = 115 | getContext().get(FilePath.class).child(step.file).read()) { 116 | if (BASE64_ENCODING.equals(step.encoding)) { 117 | return Base64.getEncoder().encodeToString(IOUtils.toByteArray(is)); 118 | } else { 119 | return IOUtils.toString(is, step.encoding); // The platform default is used if encoding is null. 120 | } 121 | } 122 | } 123 | 124 | private static final long serialVersionUID = 1L; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/DeleteDirStepTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 CLoudbees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import static org.junit.jupiter.api.Assertions.*; 28 | 29 | import hudson.FilePath; 30 | import java.io.File; 31 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 32 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 33 | import org.junit.jupiter.api.BeforeEach; 34 | import org.junit.jupiter.api.Test; 35 | import org.jvnet.hudson.test.JenkinsRule; 36 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 37 | 38 | @WithJenkins 39 | class DeleteDirStepTest { 40 | 41 | private JenkinsRule r; 42 | 43 | @BeforeEach 44 | void beforeEach(JenkinsRule rule) { 45 | r = rule; 46 | } 47 | 48 | @Test 49 | void testDeleteEmptyWorkspace() throws Exception { 50 | String workspace = runAndGetWorkspaceDir( 51 | """ 52 | node { 53 | deleteDir() 54 | }"""); 55 | File f = new File(workspace); 56 | assertFalse(f.exists(), "Workspace directory should no longer exist"); 57 | } 58 | 59 | @Test 60 | void testDeleteTopLevelDir() throws Exception { 61 | String workspace = runAndGetWorkspaceDir( 62 | """ 63 | node { 64 | writeFile file: 'f1', text: 'some text' 65 | writeFile file: 'f2', text: 'some text' 66 | writeFile file: '.hidden', text: 'some text' 67 | writeFile file: 'sub1/f1', text: 'some text' 68 | writeFile file: '.sub2/f2', text: 'some text' 69 | writeFile file: '.sub3/.hidden', text: 'some text' 70 | echo 'workspace is ---' + pwd() + '---' 71 | deleteDir() 72 | }"""); 73 | File f = new File(workspace); 74 | assertFalse(f.exists(), "Workspace directory should no longer exist"); 75 | } 76 | 77 | @Test 78 | void testDeleteSubFolder() throws Exception { 79 | String workspace = runAndGetWorkspaceDir( 80 | """ 81 | node { 82 | writeFile file: 'f1', text: 'some text' 83 | writeFile file: 'f2', text: 'some text' 84 | writeFile file: '.hidden', text: 'some text' 85 | writeFile file: 'sub1/f1', text: 'some text' 86 | writeFile file: '.sub2/f2', text: 'some text' 87 | writeFile file: '.sub3/.hidden', text: 'some text' 88 | echo 'workspace is ---' + pwd() + '---' 89 | dir ('sub1') { 90 | deleteDir() 91 | }\ 92 | }"""); 93 | 94 | File f = new File(workspace); 95 | assertTrue(f.exists(), "Workspace directory should still exist"); 96 | assertTrue(new File(f, "f1").exists(), "f1 should still exist"); 97 | assertTrue(new File(f, "f2").exists(), "f1 should still exist"); 98 | assertFalse(new File(f, "sub1").exists(), "sub1 should not exist"); 99 | assertTrue(new File(f, ".sub2/f2").exists(), ".sub2/f2 should still exist"); 100 | assertTrue(new File(f, ".sub3/.hidden").exists(), ".sub3/.hidden should still exist"); 101 | } 102 | 103 | /** 104 | * Runs the given flow and returns the workspace used. 105 | * @param flow a flow definition. 106 | * @return the workspace used. 107 | */ 108 | private String runAndGetWorkspaceDir(String flow) throws Exception { 109 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 110 | 111 | p.setDefinition(new CpsFlowDefinition(flow, true)); 112 | r.assertBuildStatusSuccess(p.scheduleBuild2(0)); 113 | 114 | FilePath ws = r.jenkins.getWorkspaceFor(p); 115 | String workspace = ws.getRemote(); 116 | assertNotNull(workspace, "Unable to locate workspace"); 117 | return workspace; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/steps/ArtifactArchiverStepTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.workflow.steps; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.io.InputStream; 7 | import java.nio.charset.StandardCharsets; 8 | import jenkins.model.ArtifactManagerConfiguration; 9 | import jenkins.util.VirtualFile; 10 | import org.apache.commons.io.IOUtils; 11 | import org.jenkinsci.plugins.workflow.DirectArtifactManagerFactory; 12 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 13 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 14 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 15 | import org.junit.jupiter.api.BeforeEach; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.extension.RegisterExtension; 18 | import org.jvnet.hudson.test.Issue; 19 | import org.jvnet.hudson.test.JenkinsRule; 20 | import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; 21 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 22 | 23 | @WithJenkins 24 | class ArtifactArchiverStepTest { 25 | 26 | @SuppressWarnings("unused") 27 | @RegisterExtension 28 | private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); 29 | 30 | private JenkinsRule r; 31 | 32 | @BeforeEach 33 | void beforeEach(JenkinsRule rule) { 34 | r = rule; 35 | } 36 | 37 | /** 38 | * Archive and unarchive file 39 | */ 40 | @Test 41 | void archive() throws Exception { 42 | // job setup 43 | WorkflowJob foo = r.jenkins.createProject(WorkflowJob.class, "foo"); 44 | foo.setDefinition(new CpsFlowDefinition( 45 | """ 46 | node { 47 | writeFile text: 'hello world', file: 'msg' 48 | archive 'm*' 49 | unarchive(mapping:['msg':'msg.out']) 50 | archive 'msg.out' 51 | }""", 52 | true)); 53 | 54 | // get the build going, and wait until workflow pauses 55 | WorkflowRun b = r.assertBuildStatusSuccess(foo.scheduleBuild2(0).get()); 56 | 57 | VirtualFile archivedFile = b.getArtifactManager().root().child("msg.out"); 58 | assertTrue(archivedFile.exists()); 59 | try (InputStream stream = archivedFile.open()) { 60 | assertEquals("hello world", IOUtils.toString(stream, StandardCharsets.UTF_8)); 61 | } 62 | r.assertLogContains(Messages.ArtifactArchiverStepExecution_Deprecated(), b); 63 | } 64 | 65 | @Issue("JENKINS-31931") 66 | @Test 67 | void nonexistent() throws Exception { 68 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 69 | p.setDefinition(new CpsFlowDefinition("node {archive 'nonexistent/'}", true)); 70 | WorkflowRun b = r.buildAndAssertSuccess(p); 71 | r.assertLogContains(Messages.ArtifactArchiverStepExecution_NoFiles("nonexistent/"), b); 72 | 73 | p.setDefinition(new CpsFlowDefinition("node { archive includes:'nonexistent/', excludes:'pants' }", true)); 74 | WorkflowRun b2 = r.buildAndAssertSuccess(p); 75 | r.assertLogContains(Messages.ArtifactArchiverStepExecution_NoFilesWithExcludes("nonexistent/", "pants"), b2); 76 | } 77 | 78 | @Test 79 | void unarchiveDir() throws Exception { 80 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 81 | p.setDefinition(new CpsFlowDefinition( 82 | """ 83 | node { 84 | writeFile text: 'one', file: 'a/1'; writeFile text: 'two', file: 'a/b/2' 85 | archive 'a/' 86 | dir('new') { 87 | unarchive mapping: ['a/' : '.'] 88 | echo "${readFile 'a/1'}/${readFile 'a/b/2'}" 89 | } 90 | } 91 | """, 92 | true)); 93 | WorkflowRun b = r.assertBuildStatusSuccess(p.scheduleBuild2(0).get()); 94 | VirtualFile archivedFile = b.getArtifactManager().root().child("a/b/2"); 95 | assertTrue(archivedFile.exists()); 96 | try (InputStream stream = archivedFile.open()) { 97 | assertEquals("two", IOUtils.toString(stream, StandardCharsets.UTF_8)); 98 | } 99 | r.assertLogContains("one/two", b); 100 | } 101 | 102 | @Issue("JENKINS-49635") 103 | @Test 104 | void directDownload() throws Exception { 105 | ArtifactManagerConfiguration.get().getArtifactManagerFactories().add(new DirectArtifactManagerFactory()); 106 | r.createSlave("remote1", null, null); 107 | r.createSlave("remote2", null, null); 108 | WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); 109 | p.setDefinition(new CpsFlowDefinition( 110 | """ 111 | node('remote1') { 112 | writeFile file: 'x', text: 'contents' 113 | archiveArtifacts 'x' 114 | } 115 | node('remote2') { 116 | unarchive mapping: [x: 'x'] 117 | echo "loaded ${readFile('x')}" 118 | } 119 | """, 120 | true)); 121 | DirectArtifactManagerFactory.whileBlockingOpen(() -> { 122 | r.assertLogContains("loaded contents", r.buildAndAssertSuccess(p)); 123 | return null; 124 | }); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/steps/SleepStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 Jesse Glick. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.steps; 26 | 27 | import edu.umd.cs.findbugs.annotations.NonNull; 28 | import hudson.Extension; 29 | import hudson.Util; 30 | import hudson.model.TaskListener; 31 | import hudson.util.ListBoxModel; 32 | import java.util.Collections; 33 | import java.util.Set; 34 | import java.util.concurrent.ScheduledFuture; 35 | import java.util.concurrent.TimeUnit; 36 | import java.util.logging.Level; 37 | import java.util.logging.Logger; 38 | import jenkins.util.Timer; 39 | import org.kohsuke.stapler.DataBoundConstructor; 40 | import org.kohsuke.stapler.DataBoundSetter; 41 | 42 | public final class SleepStep extends Step { 43 | 44 | private static final Logger LOGGER = Logger.getLogger(SleepStep.class.getName()); 45 | 46 | private final int time; 47 | 48 | private TimeUnit unit = TimeUnit.SECONDS; 49 | 50 | @DataBoundConstructor 51 | public SleepStep(int time) { 52 | this.time = time; 53 | } 54 | 55 | @DataBoundSetter 56 | public void setUnit(TimeUnit unit) { 57 | this.unit = unit; 58 | } 59 | 60 | public int getTime() { 61 | return time; 62 | } 63 | 64 | public TimeUnit getUnit() { 65 | return unit; 66 | } 67 | 68 | @Override 69 | public StepExecution start(StepContext context) throws Exception { 70 | return new Execution(this, context); 71 | } 72 | 73 | public static final class Execution extends AbstractStepExecutionImpl { 74 | 75 | private static final long serialVersionUID = 1L; 76 | 77 | private final transient SleepStep step; 78 | private long end; 79 | private transient volatile ScheduledFuture task; 80 | 81 | Execution(SleepStep step, StepContext context) { 82 | super(context); 83 | this.step = step; 84 | } 85 | 86 | @Override 87 | public boolean start() throws Exception { 88 | long now = System.currentTimeMillis(); 89 | end = now + step.unit.toMillis(step.time); 90 | setupTimer(now); 91 | return false; 92 | } 93 | 94 | private void setupTimer(long now) { 95 | TaskListener listener; 96 | try { 97 | listener = getContext().get(TaskListener.class); 98 | } catch (Exception x) { 99 | LOGGER.log(Level.WARNING, null, x); 100 | listener = TaskListener.NULL; 101 | } 102 | if (end > now) { 103 | listener.getLogger().println("Sleeping for " + Util.getTimeSpanString(end - now)); 104 | task = Timer.get().schedule(() -> getContext().onSuccess(null), end - now, TimeUnit.MILLISECONDS); 105 | } else { 106 | listener.getLogger().println("No need to sleep any longer"); 107 | getContext().onSuccess(null); 108 | } 109 | } 110 | 111 | @Override 112 | public void stop(@NonNull Throwable cause) throws Exception { 113 | if (task != null) { 114 | task.cancel(false); 115 | } 116 | super.stop(cause); 117 | } 118 | 119 | @Override 120 | public void onResume() { 121 | setupTimer(System.currentTimeMillis()); 122 | } 123 | 124 | @Override 125 | public String getStatus() { 126 | long now = System.currentTimeMillis(); 127 | if (end > now) { 128 | return "sleeping for another " + Util.getTimeSpanString(end - now); 129 | } else { 130 | return "should have stopped sleeping " + Util.getTimeSpanString(now - end) + " ago"; 131 | } 132 | } 133 | } 134 | 135 | @Extension 136 | public static final class DescriptorImpl extends StepDescriptor { 137 | 138 | @Override 139 | public String getFunctionName() { 140 | return "sleep"; 141 | } 142 | 143 | @NonNull 144 | @Override 145 | public String getDisplayName() { 146 | return "Sleep"; 147 | } 148 | 149 | public ListBoxModel doFillUnitItems() { 150 | ListBoxModel r = new ListBoxModel(); 151 | for (TimeUnit unit : TimeUnit.values()) { 152 | r.add(unit.name()); 153 | } 154 | return r; 155 | } 156 | 157 | @Override 158 | public Set> getRequiredContext() { 159 | return Collections.singleton(TaskListener.class); 160 | } 161 | 162 | // TODO argumentsToString should perhaps return "3m" etc. 163 | 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/support/steps/stash/StashStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2015 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.jenkinsci.plugins.workflow.support.steps.stash; 26 | 27 | import edu.umd.cs.findbugs.annotations.CheckForNull; 28 | import edu.umd.cs.findbugs.annotations.NonNull; 29 | import hudson.EnvVars; 30 | import hudson.Extension; 31 | import hudson.FilePath; 32 | import hudson.Launcher; 33 | import hudson.Util; 34 | import hudson.model.Run; 35 | import hudson.model.TaskListener; 36 | import java.util.Collections; 37 | import java.util.HashSet; 38 | import java.util.Map; 39 | import java.util.Set; 40 | import jenkins.model.Jenkins; 41 | import org.jenkinsci.plugins.workflow.flow.StashManager; 42 | import org.jenkinsci.plugins.workflow.steps.Step; 43 | import org.jenkinsci.plugins.workflow.steps.StepContext; 44 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor; 45 | import org.jenkinsci.plugins.workflow.steps.StepExecution; 46 | import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution; 47 | import org.kohsuke.stapler.DataBoundConstructor; 48 | import org.kohsuke.stapler.DataBoundSetter; 49 | 50 | public class StashStep extends Step { 51 | 52 | private final @NonNull String name; 53 | private @CheckForNull String includes; 54 | private @CheckForNull String excludes; 55 | private boolean useDefaultExcludes = true; 56 | private boolean allowEmpty = false; 57 | 58 | @DataBoundConstructor 59 | public StashStep(@NonNull String name) { 60 | Jenkins.checkGoodName(name); 61 | this.name = name; 62 | } 63 | 64 | @NonNull 65 | public String getName() { 66 | return name; 67 | } 68 | 69 | @CheckForNull 70 | public String getIncludes() { 71 | return includes; 72 | } 73 | 74 | @DataBoundSetter 75 | public void setIncludes(String includes) { 76 | this.includes = Util.fixEmpty(includes); 77 | } 78 | 79 | @CheckForNull 80 | public String getExcludes() { 81 | return excludes; 82 | } 83 | 84 | @DataBoundSetter 85 | public void setExcludes(String excludes) { 86 | this.excludes = Util.fixEmpty(excludes); 87 | } 88 | 89 | public boolean isUseDefaultExcludes() { 90 | return useDefaultExcludes; 91 | } 92 | 93 | @DataBoundSetter 94 | public void setUseDefaultExcludes(boolean useDefaultExcludes) { 95 | this.useDefaultExcludes = useDefaultExcludes; 96 | } 97 | 98 | public boolean isAllowEmpty() { 99 | return allowEmpty; 100 | } 101 | 102 | @DataBoundSetter 103 | public void setAllowEmpty(boolean allowEmpty) { 104 | this.allowEmpty = allowEmpty; 105 | } 106 | 107 | @Override 108 | public StepExecution start(StepContext context) throws Exception { 109 | return new Execution(this, context); 110 | } 111 | 112 | public static class Execution extends SynchronousNonBlockingStepExecution { 113 | 114 | private static final long serialVersionUID = 1L; 115 | 116 | private final transient StashStep step; 117 | 118 | Execution(StashStep step, StepContext context) { 119 | super(context); 120 | this.step = step; 121 | } 122 | 123 | @Override 124 | protected Void run() throws Exception { 125 | StashManager.stash( 126 | getContext().get(Run.class), 127 | step.name, 128 | getContext().get(FilePath.class), 129 | getContext().get(Launcher.class), 130 | getContext().get(EnvVars.class), 131 | getContext().get(TaskListener.class), 132 | step.includes, 133 | step.excludes, 134 | step.useDefaultExcludes, 135 | step.allowEmpty); 136 | return null; 137 | } 138 | } 139 | 140 | @Extension 141 | public static class DescriptorImpl extends StepDescriptor { 142 | 143 | @Override 144 | public String getFunctionName() { 145 | return "stash"; 146 | } 147 | 148 | @NonNull 149 | @Override 150 | public String getDisplayName() { 151 | return "Stash some files to be used later in the build"; 152 | } 153 | 154 | @Override 155 | public Set> getRequiredContext() { 156 | Set> context = new HashSet<>(); 157 | Collections.addAll(context, Run.class, FilePath.class, Launcher.class, EnvVars.class, TaskListener.class); 158 | return Collections.unmodifiableSet(context); 159 | } 160 | 161 | @Override 162 | public String argumentsToString(Map namedArgs) { 163 | Object name = namedArgs.get("name"); 164 | return name instanceof String ? (String) name : null; 165 | } 166 | } 167 | } 168 | --------------------------------------------------------------------------------