├── .github ├── dependabot.yml └── release-drafter.yml ├── .gitignore ├── Jenkinsfile ├── LICENSE.txt ├── README.md ├── examples └── fileLoader │ ├── environment.groovy │ └── helloworld.groovy ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── workflow │ │ └── remoteloader │ │ ├── FileLoaderDSL.java │ │ ├── GroovyFileGlobalVariable.java │ │ └── GroovyFileGlobalVariableException.java └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── plugins │ └── workflow │ └── remoteloader │ └── FileLoaderDSL │ ├── FileLoaderDSLImpl.groovy │ ├── help.jelly │ ├── sample_loadMultipleFilesFromGit.groovy │ ├── sample_loadMultipleFilesFromSVN.groovy │ ├── sample_loadSingleFileFromGit.groovy │ └── sample_loadSingleFileFromSVN.groovy └── test └── java └── org └── jenkinsci └── plugins └── workflow └── remoteloader └── FileLoaderDSLTest.java /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates 2 | --- 3 | version: 2 4 | updates: 5 | - package-ecosystem: "maven" 6 | directory: "/" 7 | labels: 8 | - "dependencies" 9 | schedule: 10 | interval: "monthly" 11 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | tag-template: workflow-remote-loader-$NEXT_MINOR_VERSION 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | work/ 3 | 4 | # IntelliJ project files 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .idea/ 9 | 10 | # eclipse project file 11 | .settings 12 | .classpath 13 | .project 14 | build/ 15 | 16 | /nb-configuration.xml 17 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | See the documentation for more options: 3 | https://github.com/jenkins-infra/pipeline-library/ 4 | */ 5 | buildPlugin( 6 | useContainerAgent: true, // Set to `false` if you need to use Docker for containerized tests 7 | configurations: [ 8 | [platform: 'linux', jdk: 21], 9 | [platform: 'windows', jdk: 17], 10 | ]) 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015, CloudBees, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pipeline Remote File Loader Plugin 2 | 3 | ## Summary 4 | 5 | **The [Pipeline: Groovy Libraries](https://plugins.jenkins.io/pipeline-groovy-lib/) plugin replaces this plugin**. 6 | The [Pipeline shared libraries section of the Jenkins User Handbook](https://jenkins.io/doc/book/pipeline/shared-libraries/) describes the [Pipeline: Groovy Libraries](https://plugins.jenkins.io/pipeline-groovy-lib/) plugin in detail. 7 | 8 | The plugin simplifies the usage of the shared functionality in [Pipeline](https://www.jenkins.io/doc/book/pipeline/) scripts. 9 | It allows Pipeline scripts to be stored in remote SCM iles and loads them on-demand. 10 | 11 | Supported features: 12 | * Groovy file loading from Git and Github (requires an installed Git plugin) 13 | 14 | ## Usage 15 | 16 | The plugin adds a global `fileLoader` DSL variable, which provides methods for loading Pipeline objects from remote sources. 17 | 18 | ### Available methods 19 | 20 | The `fileLoader` variable provides the following methods: 21 | * `fromGit(String libPath, String repository, String branch, String credentialsId, String labelExpression, boolean skipNodeCreation)` - loading of a single Groovy file from the specified Git repository 22 | * `withGit(String repository, String branch, String credentialsId, String labelExpression, boolean skipNodeCreation)` - wrapper closure for multiple files loading from a same Git repo 23 | * `fromSVN(String libPath, String repository, String credentialsId, String labelExpression, boolean skipNodeCreation)` - loading of a single Groovy file from the specified SVN repository 24 | * `withSVN(String repository, String credentialsId, String labelExpression, boolean skipNodeCreation)` - wrapper closure for multiple files loading from a same SVN repo 25 | 26 | * `load(String libPath)` - loading of an object from a Groovy file specified by the relative path. Also can be used within `withGit()` closure to load multiple objects at once 27 | 28 | Parameters: 29 | * `libPath` - a relative path to the file, ".groovy" extension will be added automatically 30 | * `repository` 31 | * for Git - string representation of a path to Git repository. Supports all formats supported by [Git Plugin](https://plugins.jenkins.io/git/) 32 | * for SVN - string representation of a path to/or inside an SVN repository. 33 | * `branch` - Optional: Branch to be used (it's also possible to specify labels). Default value: `master` 34 | * `credentialsId` - Optional: Credentials to be used for the Git repo checkout. Default value: `null` (unauthorized access) 35 | * `labelExpression` - Optional: label expression, which specifies a node to be used for checkout. Default value: empty string (runs on any node) 36 | * `skipNodeCreation` - Optional: If true the creation of a new node is skipped. Default value: false (creates a new node) 37 | 38 | ### Groovy file format 39 | 40 | The loading behaves similarly to the built-in `load` command, see [Pipeline documentation](https://www.jenkins.io/doc/pipeline/steps/workflow-cps/#load-evaluate-a-groovy-source-file-into-the-pipeline-script) for more info about library file syntax. Only one file is being loaded by commands from `fileLoader`. Use static initializers within the Groovy file of the loaded file to load more context from neighbor files. 41 | 42 | ### Examples 43 | 44 | Loading a single Groovy file from Git: 45 | ```groovy 46 | stage 'Load a file from GitHub' 47 | def helloworld = fileLoader.fromGit('examples/fileLoader/helloworld', 48 | 'https://github.com/jenkinsci/workflow-remote-loader-plugin.git', 'master', null, '') 49 | 50 | stage 'Run method from the loaded file' 51 | helloworld.printHello() 52 | ``` 53 | 54 | Loading multiple files from Git: 55 | ```groovy 56 | stage 'Load files from GitHub' 57 | def environment, helloworld 58 | fileLoader.withGit('https://github.com/jenkinsci/workflow-remote-loader-plugin.git', 'master', null, '') { 59 | helloworld = fileLoader.load('examples/fileLoader/helloworld'); 60 | environment = fileLoader.load('examples/fileLoader/environment'); 61 | } 62 | 63 | stage 'Run methods from the loaded content' 64 | helloworld.printHello() 65 | environment.dumpEnvVars() 66 | ``` 67 | 68 | ## License 69 | [MIT License](http://opensource.org/licenses/MIT) 70 | 71 | ## Changelog 72 | 73 | [GitHub releases](https://github.com/jenkinsci/workflow-remote-loader-plugin/releases) 74 | -------------------------------------------------------------------------------- /examples/fileLoader/environment.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Dumps environment varibles to the log. 3 | */ 4 | 5 | import com.cloudbees.groovy.cps.NonCPS 6 | 7 | def version = '1.0' 8 | 9 | @NonCPS 10 | def dumpEnvVars() { 11 | def str = "Dumping build environment variables...\n" 12 | for (Map.Entry entry : currentBuild.build().environment) { 13 | str += " ${entry.key} = ${entry.value}\n" 14 | } 15 | echo str 16 | } 17 | 18 | return this; 19 | -------------------------------------------------------------------------------- /examples/fileLoader/helloworld.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Prints a stub message for testing purposes. 3 | */ 4 | 5 | def version = '1.0' 6 | 7 | def printHello() { 8 | println "Hello, world!" 9 | } 10 | 11 | return this; 12 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.jenkins-ci.plugins 7 | plugin 8 | 4.81 9 | 10 | 11 | org.jenkins-ci.plugins 12 | workflow-remote-loader 13 | 1.7-SNAPSHOT 14 | hpi 15 | 16 | Jenkins Pipeline Remote Loader Plugin 17 | Allows loading Pipeline scripts from remote locations (enhanced version of the built-in load command) 18 | https://github.com/jenkinsci/workflow-remote-loader-plugin 19 | 20 | 21 | MIT License 22 | https://opensource.org/licenses/MIT 23 | 24 | 25 | 26 | 27 | 2.361.4 28 | 29 | 30 | 31 | 32 | markewaite 33 | Mark Waite 34 | mark.earl.waite@gmail.com 35 | 36 | maintainer 37 | 38 | 39 | 40 | oleg_nenashev 41 | Oleg Nenashev 42 | o.v.nenashev@gmail.com 43 | 44 | creator (retired) 45 | 46 | 47 | 48 | escoem 49 | Emilio Escobar 50 | 51 | maintainer 52 | 53 | 54 | 55 | 56 | 57 | scm:git:https://github.com/jenkinsci/${project.artifactId}-plugin.git 58 | scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git 59 | https://github.com/jenkinsci/${project.artifactId}-plugin 60 | HEAD 61 | 62 | 63 | 64 | 65 | repo.jenkins-ci.org 66 | https://repo.jenkins-ci.org/public/ 67 | 68 | 69 | 70 | 71 | 72 | repo.jenkins-ci.org 73 | https://repo.jenkins-ci.org/public/ 74 | 75 | 76 | 77 | 78 | 79 | 80 | io.jenkins.tools.bom 81 | bom-2.361.x 82 | 2102.v854b_fec19c92 83 | pom 84 | import 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.jenkins-ci.plugins 92 | script-security 93 | 94 | 95 | org.jenkins-ci.plugins.workflow 96 | workflow-cps 97 | 98 | 99 | org.jenkins-ci.plugins 100 | git 101 | test 102 | 103 | 104 | org.jenkins-ci.plugins 105 | matrix-project 106 | test 107 | 108 | 109 | org.jenkins-ci.plugins 110 | subversion 111 | test 112 | 113 | 114 | org.jenkins-ci.plugins.workflow 115 | workflow-basic-steps 116 | test 117 | 118 | 119 | org.jenkins-ci.plugins.workflow 120 | workflow-durable-task-step 121 | test 122 | 123 | 124 | org.jenkins-ci.plugins.workflow 125 | workflow-job 126 | test 127 | 128 | 129 | org.jenkins-ci.plugins.workflow 130 | workflow-step-api 131 | test 132 | 133 | 134 | org.jenkinsci.plugins 135 | pipeline-model-api 136 | test 137 | 138 | 139 | org.jenkinsci.plugins 140 | pipeline-model-definition 141 | test 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 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 | package org.jenkinsci.plugins.workflow.remoteloader; 25 | 26 | import hudson.Extension; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import org.apache.commons.io.IOUtils; 30 | import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist; 31 | import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist; 32 | import org.kohsuke.accmod.Restricted; 33 | import org.kohsuke.accmod.restrictions.NoExternalUse; 34 | 35 | /** 36 | * Provides a "fileLoader" global variable. 37 | * This variable allows to load Pipeline objects from remote locations (e.g. Git repositories). 38 | * @author Oleg Nenashev 39 | */ 40 | @Extension 41 | public class FileLoaderDSL extends GroovyFileGlobalVariable { 42 | 43 | @Override 44 | public String getName() { 45 | return "fileLoader"; 46 | } 47 | 48 | /** 49 | * Loads a snippet from the resource file. 50 | * @param name Name of the snippet (e.g. "loadMultipleFiles") 51 | * @return Workflow script text 52 | * @throws IOException Loading error 53 | */ 54 | @Restricted(NoExternalUse.class) 55 | public static String getSampleSnippet(String name) throws IOException { 56 | final String resourceName = "FileLoaderDSL/sample_" + name + ".groovy"; 57 | final InputStream scriptStream = FileLoaderDSL.class.getResourceAsStream(resourceName); 58 | if (scriptStream == null) { 59 | throw new IOException("Cannot find sample script in " + resourceName); 60 | } 61 | return IOUtils.toString(scriptStream, "UTF-8"); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/remoteloader/GroovyFileGlobalVariable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 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 | package org.jenkinsci.plugins.workflow.remoteloader; 25 | 26 | import groovy.lang.Binding; 27 | import javax.annotation.Nonnull; 28 | import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist; 29 | import org.jenkinsci.plugins.workflow.cps.CpsScript; 30 | import org.jenkinsci.plugins.workflow.cps.GlobalVariable; 31 | import org.kohsuke.accmod.Restricted; 32 | import org.kohsuke.accmod.restrictions.NoExternalUse; 33 | 34 | /** 35 | * Implements Global variable, which is implemented via Groovy file. 36 | * Exclusions should be configured separately using {@link ProxyWhitelist}. 37 | * @author Oleg Nenashev 38 | */ 39 | @Restricted(NoExternalUse.class) 40 | public abstract class GroovyFileGlobalVariable extends GlobalVariable { 41 | 42 | /** 43 | * Canonical name of the class to be loaded. 44 | * @return Canonical class name 45 | */ 46 | @Nonnull 47 | public String getClassName() { 48 | return getClass().getName() + ".FileLoaderDSLImpl"; 49 | } 50 | 51 | @Override 52 | public final Object getValue(CpsScript script) throws Exception { 53 | final Binding binding = script.getBinding(); 54 | final Object loadedObject; 55 | if (binding.hasVariable(getName())) { 56 | loadedObject = binding.getVariable(getName()); 57 | } else { 58 | // Note that if this were a method rather than a constructor, we would need to mark it @NonCPS lest it throw CpsCallableInvocation. 59 | loadedObject = script.getClass().getClassLoader().loadClass(getClassName()).getConstructor(CpsScript.class).newInstance(script); 60 | binding.setVariable(getName(), loadedObject); 61 | } 62 | return loadedObject; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/workflow/remoteloader/GroovyFileGlobalVariableException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 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 | package org.jenkinsci.plugins.workflow.remoteloader; 25 | 26 | import javax.annotation.Nonnull; 27 | 28 | /** 29 | * Exception for {@link GroovyFileGlobalVariable} management. 30 | * @author Oleg Nenashev 31 | */ 32 | class GroovyFileGlobalVariableException extends Exception { 33 | 34 | private static final long serialVersionUID = 1L; 35 | 36 | private final String variableName; 37 | 38 | public GroovyFileGlobalVariableException(@Nonnull String variableName, @Nonnull String message) { 39 | super(message); 40 | this.variableName = variableName; 41 | } 42 | 43 | public GroovyFileGlobalVariableException(@Nonnull String variableName, @Nonnull Throwable cause) { 44 | super(cause); 45 | this.variableName = variableName; 46 | } 47 | 48 | public GroovyFileGlobalVariableException(@Nonnull String variableName, @Nonnull String message, @Nonnull Throwable cause) { 49 | super(message, cause); 50 | this.variableName = variableName; 51 | } 52 | 53 | @Override 54 | public String getMessage() { 55 | return "[" + variableName + "] - " + super.getMessage(); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 25 |
26 | Allows loading Pipeline script from remote locations (enhanced version of the built-in load command) 27 |
28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL/FileLoaderDSLImpl.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 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 | package org.jenkinsci.plugins.workflow.remoteloader.FileLoaderDSL 25 | 26 | import org.jenkinsci.plugins.workflow.cps.CpsScript; 27 | 28 | class FileLoaderDSLImpl implements Serializable { 29 | 30 | private CpsScript script 31 | 32 | private static final String DEFAULT_BRANCH = 'master' 33 | //TODO: This repo does not exist. It needs something more realistic 34 | private static final String DEFAULT_REPO_URL = 'git@github.com:jenkinsci/workflow-snippets.git' 35 | private static final String TMP_FOLDER = 'libLoader' 36 | 37 | 38 | public FileLoaderDSLImpl(CpsScript script) { 39 | this.script = script 40 | } 41 | 42 | public Object fromGit(String libPath, String repoUrl = DEFAULT_REPO_URL, String repoBranch = DEFAULT_BRANCH, 43 | String credentialsId = null, labelExpression = '', boolean skipNodeCreation = false) { 44 | Object res; 45 | withGit(repoUrl, repoBranch, credentialsId, labelExpression, skipNodeCreation) { 46 | res = load(libPath) 47 | } 48 | return res 49 | } 50 | 51 | public V withGit(String repoUrl = DEFAULT_REPO_URL, String repoBranch = DEFAULT_BRANCH, 52 | String credentialsId = null, labelExpression = '', boolean skipNodeCreation = false, Closure body) { 53 | node(labelExpression, skipNodeCreation) { 54 | withTimestamper { 55 | script.dir(TMP_FOLDER) { 56 | // Flush the directory 57 | script.deleteDir() 58 | 59 | // Checkout 60 | script.echo "Checking out ${repoUrl}, branch=${repoBranch}" 61 | script.checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: repoBranch]], 62 | userRemoteConfigs: [[credentialsId: credentialsId, url: repoUrl]]] 63 | 64 | // Invoke body in the folder 65 | body(); 66 | 67 | // Flush the directory again 68 | script.deleteDir() 69 | } 70 | } 71 | } 72 | } 73 | 74 | public Object fromSVN(String libPath, String repoUrl = DEFAULT_REPO_URL, 75 | String credentialsId = null, labelExpression = '', boolean skipNodeCreation = false) { 76 | Object res; 77 | withSVN(repoUrl, credentialsId, labelExpression, skipNodeCreation) { 78 | res = load(libPath) 79 | } 80 | return res 81 | } 82 | 83 | public V withSVN(String repoUrl = DEFAULT_REPO_URL, 84 | String credentialsId = null, labelExpression = '', boolean skipNodeCreation = false, Closure body) { 85 | node(labelExpression, skipNodeCreation) { 86 | withTimestamper { 87 | script.dir(TMP_FOLDER) { 88 | // Flush the directory 89 | script.deleteDir() 90 | 91 | // Checkout 92 | script.echo "Checking out ${repoUrl}" 93 | script.checkout changelog: false, poll: false, scm: [$class: 'SubversionSCM', locations: [[credentialsId: credentialsId, local: '.', remote: repoUrl]], workspaceUpdater: [$class: 'UpdateUpdater']] 94 | 95 | 96 | // Invoke body in the folder 97 | body(); 98 | } 99 | } 100 | } 101 | } 102 | 103 | 104 | public Object load(String libPath) { 105 | def effectiveLibPath = libPath.endsWith(".groovy") ? libPath : libPath + ".groovy"; 106 | script.echo "Loading from ${effectiveLibPath}" 107 | def lib = script.load "${effectiveLibPath}" 108 | //TODO:version checks, etc. 109 | return lib; 110 | } 111 | 112 | private V node(String labelExpression = '', boolean skipNodeCreation = false, Closure body) { 113 | // TODO: don't require a new node if the current one fits labels 114 | //if (script.env.HOME != null) { 115 | // // Already inside a node block. 116 | // body() 117 | // } else 118 | if (skipNodeCreation){ 119 | body() 120 | } else { 121 | script.node(labelExpression) { 122 | body() 123 | } 124 | } 125 | } 126 | 127 | private V withTimestamper (Closure body) { 128 | // TODO: Make this thing optional if the plugin is installed 129 | //wrap([$class: 'TimestamperBuildWrapper']) { 130 | body() 131 | //} 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL/help.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | Provides methods for loading Pipeline objects from remote sources. 4 | More info about available methods and their parameters: the plugin's Wiki page 5 | 6 |

Available methods

7 | The variable provides following methods: 8 |
    9 |
  • fromGit(String libPath, String repository, String branch, String credentialsId, 10 | String labelExpression) - loading of a single Groovy file from the specified Git repository 11 |
  • 12 |
  • 13 | withGit(String repository, String branch, String credentialsId, String labelExpression) 14 | - wrapper closure for multiple files loading from a same Git repo 15 |
  • 16 |
  • fromSVN(String libPath, String repository, String credentialsId, 17 | String labelExpression) - loading of a single Groovy file from the specified SVN repository 18 |
  • 19 |
  • 20 | withSVN(String repository, String credentialsId, String labelExpression) 21 | - wrapper closure for multiple files loading from a same SVN repo 22 |
  • 23 | 24 | 25 |
  • load(String libPath) - loading of an object from a Groovy file specified by the relative path. 26 | Also can be used within `withGit()` closure to load multiple objects at once 27 |
  • 28 |
29 | 30 | Parameters: 31 |
    32 |
  • 33 | libPath - a relative path to the file, ".groovy" extension will be added automatically 34 |
  • 35 |
  • 36 | repository - for Git: string representation of a path to Git repository. 37 | Supports all formats supported by 38 | Git Plugin 39 |
  • 40 | 41 |
  • 42 | repository - for SVN string representation of a path to or inside the SVN repository. 43 |
  • 44 |
  • branch - Optional: Branch to be used (it's also possible to specify labels). 45 | Default value: master 46 |
  • 47 |
  • 48 | credentialsId - Optional: Credentials to be used for the Git repo checkout. 49 | Default value: null (unauthorized access) 50 |
  • 51 |
  • labelExpression - Optional: label expression, which specifies a node to be used for checkout. 52 | Default value: empty string (runs on any node) 53 |
  • 54 |
55 | 56 |

57 |

Examples

58 | 59 |

Loading a single Groovy file from Git:

60 |
61 |     stage 'Load a file from GitHub'
62 |     def helloworld = fileLoader.fromGit('examples/fileLoader/helloworld', 
63 |         'https://github.com/jenkinsci/workflow-remote-loader-plugin.git', 'master', null, '')
64 | 
65 |     stage 'Run method from the loaded file'
66 |     helloworld.printHello()
67 |   
68 | 69 |

Loading multiple files from Git

70 |
71 |     stage 'Load files from GitHub'
72 |     def environment, helloworld
73 |     fileLoader.withGit('https://github.com/jenkinsci/workflow-remote-loader-plugin.git', 'master', null, '') {
74 |         helloworld = fileLoader.load('examples/fileLoader/helloworld');
75 |         environment = fileLoader.load('examples/fileLoader/environment');
76 |     }
77 | 
78 |     stage 'Run methods from the loaded content'
79 |     helloworld.printHello()
80 |     environment.dumpEnvVars()
81 |   
82 | 83 |
84 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL/sample_loadMultipleFilesFromGit.groovy: -------------------------------------------------------------------------------- 1 | stage 'Load files from GitHub' 2 | def environment, helloworld 3 | fileLoader.withGit('https://github.com/jenkinsci/workflow-remote-loader-plugin.git', 'master', null, '') { 4 | helloworld = fileLoader.load('examples/fileLoader/helloworld'); 5 | environment = fileLoader.load('examples/fileLoader/environment'); 6 | } 7 | 8 | stage 'Run methods from the loaded content' 9 | helloworld.printHello() 10 | environment.dumpEnvVars() 11 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL/sample_loadMultipleFilesFromSVN.groovy: -------------------------------------------------------------------------------- 1 | stage 'Load files from GitHub' 2 | def environment, helloworld 3 | fileLoader.withSVN('https://github.com/jenkinsci/workflow-remote-loader-plugin/trunk/examples@HEAD') { 4 | helloworld = fileLoader.load('fileLoader/helloworld'); 5 | environment = fileLoader.load('fileLoader/environment'); 6 | } 7 | 8 | stage 'Run methods from the loaded content' 9 | helloworld.printHello() 10 | environment.dumpEnvVars() 11 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL/sample_loadSingleFileFromGit.groovy: -------------------------------------------------------------------------------- 1 | stage 'Load a file from GitHub' 2 | def helloworld = fileLoader.fromGit('examples/fileLoader/helloworld', 3 | 'https://github.com/jenkinsci/workflow-remote-loader-plugin.git', 'master', null, '') 4 | 5 | stage 'Run method from the loaded file' 6 | helloworld.printHello() 7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSL/sample_loadSingleFileFromSVN.groovy: -------------------------------------------------------------------------------- 1 | stage 'Load a file from GitHub' 2 | def helloworld = fileLoader.fromSVN('fileLoader/helloworld', 3 | 'https://github.com/jenkinsci/workflow-remote-loader-plugin/trunk/examples@HEAD' ) 4 | 5 | stage 'Run method from the loaded file' 6 | helloworld.printHello() 7 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/workflow/remoteloader/FileLoaderDSLTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015 Oleg Nenashev. 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 | package org.jenkinsci.plugins.workflow.remoteloader; 25 | 26 | import edu.umd.cs.findbugs.annotations.NonNull; 27 | import hudson.model.Action; 28 | import hudson.model.Node; 29 | import hudson.model.Result; 30 | import hudson.model.queue.QueueTaskFuture; 31 | import hudson.slaves.DumbSlave; 32 | import hudson.slaves.NodeProperty; 33 | import hudson.slaves.RetentionStrategy; 34 | import java.util.Collections; 35 | import org.hamcrest.Matchers; 36 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 37 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 38 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 39 | import static org.junit.Assert.assertThat; 40 | import org.junit.Rule; 41 | import org.junit.Test; 42 | import org.jvnet.hudson.test.JenkinsRule; 43 | 44 | /** 45 | * Tests of {@link FileLoaderDSL}. 46 | * @author Oleg Nenashev 47 | */ 48 | public class FileLoaderDSLTest { 49 | 50 | @Rule 51 | public JenkinsRule j = new JenkinsRule(); 52 | 53 | @Test 54 | public void loadSingleFileFromGit() throws Exception { 55 | assertSnippet("loadSingleFileFromGit", false); 56 | } 57 | 58 | @Test 59 | public void loadSingleFileFromGit_Sandbox() throws Exception { 60 | assertSnippet("loadSingleFileFromGit", true); 61 | } 62 | 63 | @Test 64 | public void loadMultipleFilesFromGit() throws Exception { 65 | assertSnippet("loadMultipleFilesFromGit", false); 66 | } 67 | 68 | @Test 69 | public void loadMultipleFilesFromGit_Sandbox() throws Exception { 70 | //TODO: This is a downside of the "environment.groovy" sample. Needs to be adjusted 71 | assertSnippetFails("loadMultipleFilesFromGit", true, 72 | "RejectedAccessException: Scripts not permitted to use method "+ 73 | "org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper build"); 74 | } 75 | 76 | private void assertSnippet(@NonNull String snippetName, boolean useSandbox) throws Exception { 77 | WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, snippetName); 78 | job.setDefinition(new CpsFlowDefinition(FileLoaderDSL.getSampleSnippet(snippetName), useSandbox)); 79 | 80 | // Run job 81 | QueueTaskFuture runFuture = job.scheduleBuild2(0, new Action[0]); 82 | assertThat("build was actually scheduled", runFuture, Matchers.notNullValue()); 83 | WorkflowRun run = runFuture.get(); 84 | 85 | j.assertBuildStatus(Result.SUCCESS, run); 86 | } 87 | 88 | private void assertSnippetFails(@NonNull String snippetName, boolean useSandbox, 89 | @NonNull String expectedMessage) throws Exception { 90 | WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, snippetName); 91 | job.setDefinition(new CpsFlowDefinition(FileLoaderDSL.getSampleSnippet(snippetName), useSandbox)); 92 | 93 | // Run job 94 | QueueTaskFuture runFuture = job.scheduleBuild2(0, new Action[0]); 95 | assertThat("build was actually scheduled", runFuture, Matchers.notNullValue()); 96 | WorkflowRun run = runFuture.get(); 97 | 98 | j.assertBuildStatus(Result.FAILURE, run); 99 | j.assertLogContains(expectedMessage, run); 100 | } 101 | } 102 | --------------------------------------------------------------------------------