# User-Power-Moves


When you get a little bit expert in your usage of the Job DSL and Plugin, you might want to try the following Power Moves:

## Run a DSL Script locally

Before you push a new DSL script to Jenkins, it's helpful to run it locally and eyeball the resulting XML. To do this follow these steps:

```plaintext
curl -O https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/job-dsl-core/@version@/job-dsl-core-@version@-jar-with-dependencies.jar
java -jar job-dsl-core-@version@-jar-with-dependencies.jar sample.dsl.groovy
```

Replace the version number with the version of Job DSL that's installed in Jenkins to get comparable results. If you already have downloaded the JAR then you can ignore step 1.

What's going on here is that there's a static main method that can run the DSL, you just have to give it a filename. It'll output all the jobs' XML to the current directory. Likewise, if you use "using" (the templates-like feature) it'll look in the current directory for a file with the name of the job appended with ".xml" at the end of it.

By default the current directory is added to the classpath to be able to import classes. When using sub-directories for scripts, the classpath differs compared to running in Jenkins where the DSL script's directory is added to the classpath. Add the `-j` command line option to use the same behavior as when running in Jenkins:

```plaintext
java -jar job-dsl-core-@version@-jar-with-dependencies.jar -j sample.dsl.groovy
```

## Access the Jenkins Environment Variables

To access the Jenkins Environment variables (such as BUILD\_NUMBER) from within DSL scripts just wrap them in '${}'. E.g.:

`println " BUILD_NUMBER = ${BUILD_NUMBER}"`

Some of the available variables are as follows:

* BUILD\_CAUSE
    
* BUILD\_CAUSE\_USERIDCAUSE
    
* BUILD\_ID
    
* BUILD\_NUMBER
    
* BUILD\_TAG
    
* EXECUTOR\_NUMBER
    
* HOME
    
* HUDSON\_HOME
    
* HUDSON\_SERVER\_COOKIE
    
* JENKINS\_HOME
    
* JENKINS\_SERVER\_COOKIE
    
* JOB\_NAME
    
* LANG
    
* LOGNAME
    
* NODE\_LABELS
    
* NODE\_NAME
    
* OLDPWD
    
* PWD
    
* SHELL
    
* TERM
    
* TMPDIR
    
* USER
    

[Original discussion on the newsgroup](https://groups.google.com/d/msg/job-dsl-plugin/ArgUBsLgumo/v77k5G6fllkJ)

## Parameterized Seed Job

Build parameters are exposed as environment variables in Jenkins. A seed job build parameter named `FOO` is available as `FOO` variable in the DSL scripts. See the section about environment variables above.

## Reading Files from your Job Workspace

The job you create could be running on Jenkins agent, while the plugin runs on Jenkins master. Which means you shouldn't directly reference files on filesystem, since we're in a distributed system. The good news is that we added a method to help with this. See the docs for "Reading Files from Workspace" on [https://github.com/jenkinsci/job-dsl-plugin/wiki/Job-DSL-Commands](https://github.com/jenkinsci/job-dsl-plugin/wiki/Job-DSL-Commands)

[Original discussion on the newsgroup](https://groups.google.com/forum/#!msg/job-dsl-plugin/wjrHEI7BLx8/zxW7j7xcWOcJ)

## Understanding config.xml Generation - Multiple Calls to the Same Command

Knowing when to overwrite or append to the XML is a fundamental problem with our approach. In the beginning of the project we though to append always, but we quickly learned that it takes a lot more work to intelligently append. We then took the approach to append when possible and easy, otherwise just overwrite. Since then many users have found themselves just building up jobs from scratch and not worrying about existing values in templates, essentially taking a "we leave you alone if you leave us alone" approach.

I'd be interested in hearing from the community how often templates are used (aka using() syntax) and if the manipulations are additive (adding to exist structures) or constructive (creating new structures).

Users should also note that we're pretty bad about multiple calls being made in your DSL script to the same command, and we could be better. E.g. calling environmentVariables multiple times would leave the result of the last call as the winner. An alternative to this would be to defer its creation, accumulating the vars as we went. Once again, that takes more work and its something we can add later if needed. We should also document this better. So, if people see one behavior or other, please add it to the docs or bring it to our attention.

[Original discussion on the newsgroup](https://groups.google.com/forum/#!msg/job-dsl-plugin/5YGgR8px7gE/fP6AL71BUrkJ)

## Have Multiple SVN Locations

If you want more than one SVN location in your SCM block:

```plaintext
scm {
  svn('http://svn-mirror.xxx.lan/svn/internal/zzz/trunk', 'trunk') {
    it / locations << 'hudson.scm.SubversionSCM_-ModuleLocation' {
      remote 'http://svn-mirror.xxx.lan/svn/zzz/trunk'
      local 'trunk/community'
    }
  }
}
```

[Original discussion on the newsgroup](https://groups.google.com/forum/#!msg/job-dsl-plugin/EWCaCYJgfsE/X_5ci3AX4pAJ)

## Using Libraries

Libraries can be used in a Job DSL script by adding them to the *Additional classpath* option in the *Process Job DSLs* build step. The library's JAR files must be available in the workspace of the seed job. For libraries without transitive dependencies this can be achieved by using the *Artifact Resolver* build step of the [Repository Connector Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Repository+Connector+Plugin) prior to the *Process Job DSLs* build step. For more complex setups, an extra [Gradle](http://www.gradle.org/) build step ([Gradle Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Gradle+Plugin)) can be used.

For example, to use [Kohsuke's GitHub API](http://github-api.kohsuke.org/), the following `build.gradle` will copy all necessary libraries to a `lib` directory:

```plaintext
defaultTasks 'libs'

repositories {
    jcenter()
}

configurations {
    libs
}

dependencies {
    libs 'org.kohsuke:github-api:1.70'
}

task clean(type: Delete) {
    delete 'lib'
}

task libs(type: Copy) {
    into 'lib'
    from configurations.libs
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.2.1'
}
```

The *Additional classpath* option in the *Process Job DSLs* build step must be set to `lib/*.jar` to pick up all libraries. And then the library can be used in a Job DSL script:

```plaintext
import org.kohsuke.github.GitHub

def gh = GitHub.connectAnonymously()
gh.getOrganization('jenkinsci').listRepositories().each { repo ->
    job(repo.name) {
        scm {
            gitHub(repo.fullName)
        }
        steps {
            // ...
        }
    }
}
```

## List the Files in a Jenkins Jobs Workspace

Sometimes you want your DSL script to be able to grab a list of the files in the workspace. Use the Hudson API to achieve this:

```plaintext
hudson.FilePath workspace = hudson.model.Executor.currentExecutor().getCurrentWorkspace()
```

## Change the name of the root node

If you don't want the output job config.xml to start with a "project" node, you can use this little hack:

```plaintext
configure { project ->
    project.name = 'com.cloudbees.plugins.flow.BuildFlow'
}
```

But note, this will only work if the BuildFlow project type uses the same sub-elements as the free style project type. If this is not the case, you need to modify the root node further and things will get even uglier. (Hint, you can use configure)

## Use DSL scripts in a Gradle project

Gradle provides a way to build and test your scripts and supporting classes. See [Job DSL Gradle Example](https://github.com/sheehan/job-dsl-gradle-example) or [Job DSL Sample](https://github.com/unguiculus/job-dsl-sample) for an example.

## Use Job DSL in Pipeline scripts

Starting with version 1.48, the Job DSL build step can be used in [Pipeline](https://github.com/jenkinsci/pipeline-plugin) scripts (e.g. in `Jenkinsfile`). In version 1.49 Pipeline support has been improved by enabling a more concise syntax when using *Pipeline: Groovy* 2.10 or later.

Pipeline syntax with version 1.49 and *Pipeline: Groovy* 2.10 or later:

```plaintext
node {
    jobDsl scriptText: 'job("example-2")'

    jobDsl targets: ['jobs/projectA/*.groovy', 'jobs/common.groovy'].join('\n'),
           removedJobAction: 'DELETE',
           removedViewAction: 'DELETE',
           lookupStrategy: 'SEED_JOB',
           additionalClasspath: ['libA.jar', 'libB.jar'].join('\n'),
           additionalParameters: [message: 'Hello from pipeline', credentials: 'SECRET']
}
```

Pipeline syntax with version 1.48 or *Pipeline: Groovy* 2.9 and older:

```plaintext
node {
    step([
        $class: 'ExecuteDslScripts',
        scriptText: 'job("example-2")'
    ])
    step([
        $class: 'ExecuteDslScripts',
        targets: ['jobs/projectA/*.groovy', 'jobs/common.groovy'].join('\n'),
        removedJobAction: 'DELETE',
        removedViewAction: 'DELETE',
        lookupStrategy: 'SEED_JOB',
        additionalClasspath: ['libA.jar', 'libB.jar'].join('\n'),
        additionalParameters: [message: 'Hello from pipeline', credentials: 'SECRET']
    ])
}
```

Options:

* `targets`: optional, specifies Job DSL script files to execute, newline separated list of file names relative to the workspace
    
* `scriptText`: optional, specifies an inline Job DSL script
    
* `ignoreMissingFiles`: optional, defaults to `false`, set to `true` to ignore missing files or empty wildcards in `targets`
    
* `ignoreExisting`: optional, defaults to `false`, set to `true` to not update existing jobs and views
    
* `removedJobAction`: optional, set to `'DELETE'` or `'DISABLE'` to delete or disable jobs that have been removed from DSL scripts, defaults to `'IGNORE'`
    
* `removedViewAction`: optional, set to `'DELETE'` to delete views that have been removed from Job DSL scripts, defaults to `'IGNORE'`
    
* `removedConfigFilesAction`: optional, set to `'DELETE'` to delete config files that have been removed from Job DSL scripts, defaults to `'IGNORE'`
    
* `lookupStrategy`: optional, when set to `'SEED_JOB'` job names will be interpreted as relative to the pipeline job, defaults to `'JENKINS_ROOT` which will treat all job names as absolute
    
* `additionalClasspath`: optional, newline separated list of additional classpath entries for Job DSL scripts, file names must be relative to the workspace; this option will be ignored when script security for Job DSL is enabled on the "Configure Global Security" page
    
* `additionalParameters`: optional map which defines global variables accessible in Job DSL scripts
    
* `sandbox`: optional, defaults to `false`, if `false` the DSL script needs to be approved by an administrator; set to `true` to run the DSL scripts in a sandbox with limited abilities (see \[\[Script Security\]\]); this option will be ignored when script security for Job DSL is disabled on the "Configure Global Security" page
    

> ⚠ **Note**: when using multiple Job DSL build steps in a single pipeline, set `removedJobAction`, `removedViewAction` or `removedConfigFilesAction` to `DELETE` (or `DISABLE`) only for the last Job DSL build step. Otherwise jobs, views or config files may be deleted and re-created (or disabled and re-enabled) and you may loose the job history of generated jobs. See [JENKINS-44142](https://issues.jenkins-ci.org/browse/JENKINS-44142) for details.
