This repository conatins Jenkins Job DSL code for generating Jenkins jobs on several edx.org Jenkins servers including tools-edx-jenkins. It has a companion private repo for generating the Jobs on the edx.org Jenkins servers. Usage of this code without that repo may be difficult.
This code is in active development.
While this repo is open source in the hopes that it would be useful, it's heavily entanged with a private repo to the point where, practically it doesn't work without the private repo. While open to PRs, it's impractical for anyone outside edx to use it.
See README-Hacking for details on how to spin up a local docker container with an environment similar to one you would find on the DevOps "Tools Jenkins".
.
├── <project> # Example project name e.g. mobile app
│ ├── jobs # Job DSL code
│ ├── resources # Resources specific to this project
├── <other_project> # Another project name e.g. platform
│ ├── jobs # Job DSL code
│ ├── resources # Resources specific to this project
├── <...> # A folder for every project!
├── src # Code shared between each project
│ ├── main
│ │ ├── groovy # support classes
│ │ └── resources
│ │ └── idea.gdsl # IDE support for IDEA
│ └── test
│ └── groovy # specs (organized by project)
│ └──<project>
│ └──<other_project>
└── build.gradle # build file
DSL jobs can be tested using the Spock test framework.
To run all of the test specs:
./gradlew test
To run all of the test specs within a given project:
./gradlew test --tests sample.*
To run all a single test spec:
./gradlew test --tests sample.SampleJobSpec
You can run codenarc to verify well written Groovy code.
To run codenarc on the dsl jobs:
./gradlew codenarcJobs
To run codenarc on the shared code:
./gradlew codenarcSrc
etc...
If a job is causing problems and you want to disable it and add the reason to the job description you can use code like the following.
return dslFactory.job(extraVars.get("FOLDER_NAME") + "/${environment}-${deployment}-${jobName}") {
...
// Disabled until https://example.atlassian.net/browse/EX-123 is resolved
disabled()
description('Disabled until <a href="https://example.atlassian.net/browse/EX-123">EX-123</a> is resolved.')
...
An example job can be found here.
Several techniques for managing credentials and secrets are discussed here
https://openedx.atlassian.net/wiki/display/TE/Jenkins+secrets+management+with+Job+DSL
In addition to the yaml parsing techniques in the wiki link above, you can also manage shared constants directly in your DSL script.
- Use a try/catch to parse the Yaml file into a map
Map constantsMap = [:]
try {
out.println('Parsing secret YAML file')
String constantsConfig = new File("${EDX_PLATFORM_SHARED_CONSTANTS}").text
Yaml yaml = new Yaml()
constantsMap = yaml.load(constantsConfig)
out.println('Successfully parsed secret YAML file')
}
catch (any) {
out.println('Jenkins DSL: Error parsing secret YAML file')
out.println('Exiting with error code 1')
return 1
}
- Assert that the map contains the desired constants
- Use the constant as the key value in the map ex. constantsMap['credential']
Constant | Purpose | Use |
---|---|---|
credential | Allow access to private git repositories | In the credential() function in the Git Scm Context |
TL;DR Making a new job? Make it look like this one NOT like this one.
There are two common ways to write jobs: 1: The Build Jenkins jobs were often flattened (as shown in backupJenkins.groovy ) or if there are many jobs that are similar you can loop over a list of Maps like we did in upgradePythonRequirements.groovy. This has the benefit of keeping all the logic in one file and being easy to understand. The Build Jenkins server is now retired, but the same patterns can be relevant for jobs running in other Jenkins servers. 2: DevOps and Data Engineering jenkins jobs have often wrapped jobs in classes (as shown in AggregateDailyTrackingLogs.groovy). This paradigm has the benefit of allowing you to import the class in multiple places to be DRYer. There are also a few places where we link configuration to static functions from classes like we do in createJobs.groovy.
In general we would like to transition away from using classes in order to make it easier for people to reason about our code. To that end, please use the first methodology when possible.
1: As of this writing Tools Jenkins has not been upgraded to Jenkins 2 and does not support pipelines. 2: As of this writing our Data Engineering instance defines credentials globally and does not use seed jobs that deploy jobs into separate folders with separate credentials. 3: We want to reduce the number of git checkouts so that our jobs can still run when GitHub is down, especially for jobs that are triggered frequently.