The talk gives an example on how to introduce the Job DSL Plugin in a real life company. After explaining the importance of Configuration as Code and why we use the Job DSL Plugin for it, I will show how to take it to the next level. That means Configuration as Code does not automatically solve all configuration problems, there are a lot of pitfalls people need to look out for. On the one hand, you have to give people the freedom they need, one the other you always have to assure quality and stability at the same time.
1. An example on how to introduce the Job DSL Plugin in a real life company
Rule Jenkins with Configuration as Code
Jenkins World, 14.09.2016
2. ….…............................ An example on how to introduce Job DSL in a real life company
What this talk is about
• Configuration as code with the Job DSL Plugin
• How to take it to the next level
• Pitfalls and how to make them foolproof
Intro Configuration as Code Test your codeThe next level
3. An example on how to introduce Job DSL in a real life company
What this talk is not about
• Job DSL in detail – please refer to:
Adoption of the Job DSL Plugin at Netflix
by Justin Ryan
Configuration as Code: The Job DSL Plugin
by Daniel Spilker at JUC Europe 2015
Jenkins + Groovy with the Job DSL Plugin
by Matt Sheehan at GR8Conf US 2015
….…............................Intro Configuration as Code Test your codeThe next level
4. Christian Rasp / christian.rasp@PAYBACK.net / @crasp
An example on how to introduce Job DSL in a real life company
• Software Developer DevOps
• Jenkins & Nexus Admin
• Build Engineer for CI & CD
….…............................Intro Configuration as Code Test your codeThe next level
5. PAYBACK is continuously expanding into new countries
An example on how to introduce Job DSL in a real life company
2000
2009
2014 2010
2012
2015
….…............................Intro Configuration as Code Test your codeThe next level
6. PAYBACK – Biggest loyalty program and largest multichannel marketing platform
An example on how to introduce Job DSL in a real life company
In 2015, 20 bn coupons were distributed to
customers in Germany
Points to the value of € 338 m were
collected in 2015
95% of all PAYBACK points get
redeemed!
8 out of 10 Germans are familiar
with the PAYBACK brand
Sales of more than € 27 bn
are generated with PAYBACK cards
at partner stores (2015)
The PAYBACK card is the third most
important card in German wallets
(after debit cards and credit cards, TNS Emnid survey, 2014)
….…............................Intro Configuration as Code Test your codeThe next level
7. An example on how to introduce Job DSL in a real life company
In May 2015 PAYBACK was launched in the US under the name "Plenti"
….…............................Intro Configuration as Code Test your codeThe next level
8. ….…............................ An example on how to introduce Job DSL in a real life company
Intro Configuration as Code Test your codeThe next level
Configuration as code with the Job DSL Plugin
9. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
The initial problem
10. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
The initial problem
11. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
• Is the job still in use?
The initial problem
12. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
The initial problem
13. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
The initial problem
14. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
The initial problem
15. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
The initial problem
16. An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
All Jenkins job configuration is setup manually:
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for a group of jobs?
The initial problem
17. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
18. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
19. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
• Templates
20. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
• Templates
• Job generator Plugin
21. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
• Templates
• Job generator Plugin
• REST API or CLI
22. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
• Templates
• Job generator Plugin
• REST API or CLI
• Pipeline Plugin
23. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
• Templates
• Job generator Plugin
• REST API or CLI
• Pipeline Plugin
• Job DSL Plugin
24. Possible solutions
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• Script console
• Templates
• Job generator Plugin
• REST API or CLI
• Pipeline Plugin
• Job DSL Plugin
25. Describe jobs using a Groovy-based language
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
26. Describe jobs using a Groovy-based language
An example on how to introduce Job DSL in a real life company
mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
logRotator(-1, 30)
jdk('jdk-1.8.0_45')
wrappers {
mavenRelease {
releaseGoals('-Dresume=false release:prepare release:perform')
dryRunGoals('-Dresume=false -DdryRun=true release:prepare')
numberOfReleaseBuildsToKeep(2)
selectScmCredentials(true)
}
}
goals('clean install --batch-mode --update-snapshots')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk") {
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
….…............................Intro Configuration as Code Test your codeThe next level
27. Describe jobs using a Groovy-based language
An example on how to introduce Job DSL in a real life company
mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
logRotator(-1, 30)
jdk('jdk-1.8.0_45')
wrappers {
mavenRelease {
releaseGoals('-Dresume=false release:prepare release:perform')
dryRunGoals('-Dresume=false -DdryRun=true release:prepare')
numberOfReleaseBuildsToKeep(2)
selectScmCredentials(true)
}
}
goals('clean install --batch-mode --update-snapshots')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk") {
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
….…............................Intro Configuration as Code Test your codeThe next level
28. It still does not fit our needs
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for subset of jobs?
29. It still does not fit our needs
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for subset of jobs?
30. It still does not fit our needs
An example on how to introduce Job DSL in a real life company
• New scripting language
• New DSL reference to learn
….…............................Intro Configuration as Code Test your codeThe next level
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for subset of jobs?
31. An example on how to introduce Job DSL in a real life company
How to take it to the next level
….…............................Intro Configuration as Code Test your codeThe next level
32. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
33. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
• Standard log rotation
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
34. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
• Standard log rotation
• Configuration pitfalls
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
35. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
• Standard log rotation
• Configuration pitfalls
• Credentials for tech. users
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
36. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
• Standard log rotation
• Configuration pitfalls
• Credentials for tech. users
• Naming conventions
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
37. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
• Standard log rotation
• Configuration pitfalls
• Credentials for tech. users
• Naming conventions
• Jenkins Maven magic
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
38. Make a developers life as easy as possible
An example on how to introduce Job DSL in a real life company
• Standard log rotation
• Configuration pitfalls
• Credentials for tech. users
• Naming conventions
• Jenkins Maven magic
• Default settings
Things a Jenkins user should not need to know about:
….…............................Intro Configuration as Code Test your codeThe next level
39. So what IS the next level?
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
40. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
41. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
42. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
• Convention
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
43. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
• Convention
• Clean project structure
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
44. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
• Convention
• Clean project structure
• Dependency management
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
45. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
• Convention
• Clean project structure
• Dependency management
• Reviews
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
46. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
• Convention
• Clean project structure
• Dependency management
• Reviews
• Tests!
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
47. So what IS the next level?
An example on how to introduce Job DSL in a real life company
• Inheritance
• Standards
• Convention
• Clean project structure
• Dependency management
• Reviews
• Tests!
• More tests!
….…............................Intro Configuration as Code Test your codeThe next level
Build your own tool with standard software engineering approaches:
48. mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
logRotator(-1, 30)
jdk('jdk-1.8.0_45')
wrappers {
mavenRelease {
releaseGoals('-Dresume=false release:prepare release:perform')
dryRunGoals('-Dresume=false -DdryRun=true release:prepare')
numberOfReleaseBuildsToKeep(2)
selectScmCredentials(true)
}
}
goals('clean install --batch-mode --update-snapshots')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk")
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
49. mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
jdk('jdk-1.8.0_45')
wrappers {
mavenRelease {
releaseGoals('-Dresume=false release:prepare release:perform')
dryRunGoals('-Dresume=false -DdryRun=true release:prepare')
numberOfReleaseBuildsToKeep(2)
selectScmCredentials(true)
}
}
goals('clean install --batch-mode --update-snapshots')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk")
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
50. mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
wrappers {
mavenRelease {
releaseGoals('-Dresume=false release:prepare release:perform')
dryRunGoals('-Dresume=false -DdryRun=true release:prepare')
numberOfReleaseBuildsToKeep(2)
selectScmCredentials(true)
}
}
goals('clean install --batch-mode --update-snapshots')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk")
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
51. mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
goals('clean install --batch-mode --update-snapshots')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk")
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
52. mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
mavenInstallation('maven-3.2.2')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk")
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
53. mavenJob('HAL9000') {
description('I'm sorry Dave, I'm afraid I can't do that')
scm {
svn {
location("${Repositories.DISCOVERY.url()}/dave/trunk")
checkoutStrategy(SvnCheckoutStrategy.UPDATE_WITH_REVERT)
}
}
[...]
Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
….…............................Intro Configuration as Code Test your codeThe next level
54. Reduce the configuration to a bare minimum
An example on how to introduce Job DSL in a real life company
new MavenJobBuilder(this, 'HAL9000').make {
description("I'm sorry Dave, I'm afraid I can't do that")
svn(Repositories.DISCOVERY, '/trunk')
}
….…............................Intro Configuration as Code Test your codeThe next level
55. Use builder pattern to create simple job builders
An example on how to introduce Job DSL in a real life company
http://mrhaki.blogspot.de/2011/11/groovy-goodness-create-simple-builders.html
Groovy Goodness from
the Blog of MrHaki
….…..................….......Intro Configuration as Code Test your codeThe next level
56. Use builder pattern to create simple job builders
An example on how to introduce Job DSL in a real life company
// Build your own closures to expand Job DSL
private runClosure(Closure runClosure) {
// Create clone of closure for threading access.
Closure runClone = runClosure.clone()
// Set delegate of closure to this builder.
runClone.delegate = this
// And only use this builder as the closure delegate.
runClone.resolveStrategy = Closure.DELEGATE_ONLY
// Run closure code.
runClone()
}
http://mrhaki.blogspot.de/2011/11/groovy-goodness-create-simple-builders.html
Groovy Goodness from
the Blog of MrHaki
….…..................….......Intro Configuration as Code Test your codeThe next level
57. Use builder pattern to create simple job builders
An example on how to introduce Job DSL in a real life company
// Build your own closures to expand Job DSL
private runClosure(Closure runClosure) {
// Create clone of closure for threading access.
Closure runClone = runClosure.clone()
// Set delegate of closure to this builder.
runClone.delegate = this
// And only use this builder as the closure delegate.
runClone.resolveStrategy = Closure.DELEGATE_ONLY
// Run closure code.
runClone()
}
http://mrhaki.blogspot.de/2011/11/groovy-goodness-create-simple-builders.html
Groovy Goodness from
the Blog of MrHaki
….…..................….......Intro Configuration as Code Test your codeThe next level
// Delegate everything else to Job DSL
def methodMissing(String name, argument) {
job.invokeMethod(name, (Object[]) argument)
}
58. Use builder pattern to create simple job builders
An example on how to introduce Job DSL in a real life company
http://mrhaki.blogspot.de/2011/11/groovy-goodness-create-simple-builders.html
Groovy Goodness from
the Blog of MrHaki
….…..................….......Intro Configuration as Code Test your codeThe next level
new JobBuilder(this, 'adjust-permissions').make {
// Own function via runClosure
restrictPermissions('ernie', 'bert', 'jenkins-admins')
// Original Job DSL syntax via methodMissing
steps {
shell('ls -l')
}
}
59. Set some standards automatically
public class JobBuilder extends Builder {
protected Job job
// Create a new job object
JobBuilder(DslFactory dslFactory, String jobName) {
this.job = dslFactory.job(jobName)
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
60. Set some standards automatically
public class JobBuilder extends Builder {
protected Job job
// Create a new job object
JobBuilder(DslFactory dslFactory, String jobName) {
this.job = dslFactory.job(jobName)
}
// Defines initial state for a job
Job make(Closure additionalConfig) {
// Standards for all jobs
job.logRotator
job.jdk
job.label
// every other configurations
runClosure additionalConfig
job
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
61. Set some standards automatically
// Defines initial state for a job
Job make(Closure additionalConfig) {
// Standards for all jobs
job.logRotator
job.jdk
job.label
// every other configurations
runClosure additionalConfig
job
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
mavenJob('HAL9000') {
[...]
logRotator(-1, 30)
jdk('jdk-1.8.0_45')
[...]
}
62. Set some standards automatically
// Defines initial state for a job
Job make(Closure additionalConfig) {
// Standards for all jobs
job.logRotator
job.jdk
job.label
// every other configurations
runClosure additionalConfig
job
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
mavenJob('HAL9000') {
[...]
logRotator(-1, 30)
jdk('jdk-1.8.0_45')
[...]
}
63. Set some standards automatically
// Defines initial state for a job
Job make(Closure additionalConfig) {
// Standards for all jobs
job.logRotator
job.jdk
job.label
// every other configurations
runClosure additionalConfig
job
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
mavenJob('HAL9000') {
[...]
logRotator(-1, 30)
jdk('jdk-1.8.0_45')
[...]
}
What are the standard settings?
64. Hide complex configuration settings
An example on how to introduce Job DSL in a real life company
class MavenJobBuilder extends JobBuilder {
MavenJobBuilder(DslFactory dslFactory, String jobName) {
super(dslFactory.mavenJob(jobName))
}
MavenJob make(Closure additionalConfig) {
job.wrappers {
mavenRelease {
releaseGoals
numberOfReleaseBuildsToKeep
}
}
job.goals
job.mavenInstallation
[...]
super.make(additionalConfig)
job as MavenJob
}
}
….…..................….......Intro Configuration as Code Test your codeThe next level
65. Hide complex configuration settings
An example on how to introduce Job DSL in a real life company
job.wrappers {
mavenRelease {
releaseGoals
numberOfReleaseBuildsToKeep
}
}
job.goals
job.mavenInstallation
….…..................….......Intro Configuration as Code Test your codeThe next level
66. Hide complex configuration settings
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
new MavenJobBuilder(this, 'YourEasyMavenJobHere').make {
[...]
}
67. Encapsulate common DSL patterns
void svn(Repositories repository,
String loc,
String dir = '.',
SvnCheckoutStrategy strategy = SvnCheckoutStrategy.UPDATE_WITH_REVERT) {
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
68. Encapsulate common DSL patterns
void svn(Repositories repository,
String loc,
String dir = '.',
SvnCheckoutStrategy strategy = SvnCheckoutStrategy.UPDATE_WITH_REVERT) {
job.scm {
svn {
location("${repository.url()}${loc}") {
credentials(repository.credential())
directory(dir)
}
checkoutStrategy(strategy)
}
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
69. Encapsulate common DSL patterns
svn(Repositories.FOO, '/UTIL/trunk')
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
70. Encapsulate common DSL patterns
svn(Repositories.FOO, '/UTIL/trunk')
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
71. Encapsulate common DSL patterns
svn(Repositories.FOO, '/UTIL/trunk')
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
Why is it configured that way?
72. Encapsulate common DSL patterns
void cron(Cron c) {
job.triggers {
cron(c.getTab())
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
73. Encapsulate common DSL patterns
void cron(Cron c) {
job.triggers {
cron(c.getTab())
}
}
enum Cron {
FIVE_MINUTES( 'H/5 * * * *', 'Once in five minutes'),
FIFTEEN_MINUTES( 'H/15 * * * *', 'Once in fifteen minutes'),
THIRTY_MINUTES( 'H/30 * * * *', 'Once every thirty minutes'),
HOURLY( 'H * * * *', 'Once an hour'),
WEEKDAY_TWO_HOURLY('H 8-18/2 * * 1-5', 'Once every two hours every weekday'),
MIDNIGHT( 'H H(0-2) * * *', 'Once right after midnight'),
DAILY( 'H H * * *', 'Once a day'),
WEEKLY( 'H H * * H', 'Once a week'),
MONTHLY( 'H H H * *', 'Once a month')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
74. Encapsulate common DSL patterns
cron(Cron.FIFTEEN_MINUTES)
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
75. Easy-to-read configurations
new JobBuilder(this, 'run-script').make {
steps {
shell('''ssh $KEY_FILE $USER@FOO <<'END' java -jar cli.jar PROJECTIMPORT
-host localhost
-port 12345
-HTTP
-user "${USER}"
-password "${PASSWORD}"
-project "${PROJECT_NAME}"
-projectFile "${PROJECT_FILE}"
-dbuser '"$(grep "content.jdbc.USER" database.conf | cut -d "=" -f2-)"'
-dbpassword '"$(grep "content.jdbc.PASSWORD" database.conf | cut -d "=" -f2-)"'
-dburl '"$(grep "content.jdbc.URL" database.conf | cut -d "=" -f2-)"'
-dbschema '"$(grep "content.jdbc.SCHEMA" database.conf | cut -d "=" -f2-)"'
END''')
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
76. Easy-to-read configurations
new JobBuilder(this, 'run-script').make {
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
def scriptfile = readFileFromWorkspace('src/main/resources/bin/scriptfile.sh')
steps {
shell(scriptfile)
}
}
77. Easy-to-read configurations
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
78. Easy-to-read configurations
new MavenJobBuilder(this, 'build-new-deathstar').make {
svn(Repositories.DARKEMPIRE, '/spaceships/deathstar/shapes/ball')
cronScm(Cron.EVERY_MOVIE)
sendMail('darth.vader@empire.dark.net')
sendMail('sheev.palpatine@empire.dark.net')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
79. Easy-to-read configurations
new MavenJobBuilder(this, 'build-new-deathstar').make {
svn(Repositories.DARKEMPIRE, '/spaceships/deathstar/shapes/ball')
cronScm(Cron.EVERY_MOVIE)
sendMail('darth.vader@empire.dark.net')
sendMail('sheev.palpatine@empire.dark.net')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
new MavenJobBuilder(this, 'build-super-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.WEEKLY)
expandMavenGoals('--activate-profiles super')
}
80. Easy-to-read configurations
new MavenJobBuilder(this, 'build-new-deathstar').make {
svn(Repositories.DARKEMPIRE, '/spaceships/deathstar/shapes/ball')
cronScm(Cron.EVERY_MOVIE)
sendMail('darth.vader@empire.dark.net')
sendMail('sheev.palpatine@empire.dark.net')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
new MavenJobBuilder(this, 'build-super-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.WEEKLY)
expandMavenGoals('--activate-profiles super')
}
new MavenJobBuilder(this, 'build-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.DAILY)
reportEmpireAcceptanceTests()
}
81. Easy-to-read configurations
new MavenJobBuilder(this, 'build-new-deathstar').make {
svn(Repositories.DARKEMPIRE, '/spaceships/deathstar/shapes/ball')
cronScm(Cron.EVERY_MOVIE)
sendMail('darth.vader@empire.dark.net')
sendMail('sheev.palpatine@empire.dark.net')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
new MavenJobBuilder(this, 'build-super-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.WEEKLY)
expandMavenGoals('--activate-profiles super')
}
new MavenJobBuilder(this, 'build-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.DAILY)
reportEmpireAcceptanceTests()
}
Who is responsible for this job?
82. Easy-to-read configurations
new MavenJobBuilder(this, 'build-new-deathstar').make {
svn(Repositories.DARKEMPIRE, '/spaceships/deathstar/shapes/ball')
cronScm(Cron.EVERY_MOVIE)
sendMail('darth.vader@empire.dark.net')
sendMail('sheev.palpatine@empire.dark.net')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
new MavenJobBuilder(this, 'build-super-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.WEEKLY)
expandMavenGoals('--activate-profiles super')
}
new MavenJobBuilder(this, 'build-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.DAILY)
reportEmpireAcceptanceTests()
}
Who is responsible for this job?
What is this job doing?
83. Easy-to-read configurations
new MavenJobBuilder(this, 'build-new-deathstar').make {
svn(Repositories.DARKEMPIRE, '/spaceships/deathstar/shapes/ball')
cronScm(Cron.EVERY_MOVIE)
sendMail('darth.vader@empire.dark.net')
sendMail('sheev.palpatine@empire.dark.net')
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
new MavenJobBuilder(this, 'build-super-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.WEEKLY)
expandMavenGoals('--activate-profiles super')
}
new MavenJobBuilder(this, 'build-star-destroyers').make {
svn(Repositories.DARKEMPIRE, '/spaceships/destroyers')
cronScm(Cron.DAILY)
reportEmpireAcceptanceTests()
}
How to change settings for
a group of jobs?
Who is responsible for this job?
What is this job doing?
84. Easy-to-read configurations
DevEnvironment.values().each { environment ->
new DeployJobBuilder(this, 'Deploy-${environment.getEnvName()}').make {
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
85. Easy-to-read configurations
DevEnvironment.values().each { environment ->
new DeployJobBuilder(this, 'Deploy-${environment.getEnvName()}').make {
job.environmentVariables {
env('ENVIRONMENT_NAME', environment.getEnvName())
env('BRANCH', environment.getBranch())
env('TEST_DATA', environment.getTestData())
if (DevEnvironment.UAT.equals(environment)) {
env('UAT', true)
}
[...]
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
86. Easy-to-read configurations
DevEnvironment.values().each { environment ->
new DeployJobBuilder(this, 'Deploy-${environment.getEnvName()}').make {
job.environmentVariables {
env('ENVIRONMENT_NAME', environment.getEnvName())
env('BRANCH', environment.getBranch())
env('TEST_DATA', environment.getTestData())
if (DevEnvironment.UAT.equals(environment)) {
env('UAT', true)
}
[...]
}
}
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
enum DevEnvironment {
STAGE1('system-integration', Branch.SIT, '#customer'),
STAGE2('performance', Branch.PRF, '#customer'),
UAT( 'external-test', Branch.ET, '#customer#partner'),
PROD( 'production', Branch.MASTER, '#full')
}
87. Project structure
.
├── pom.xml # build file
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
88. Project structure
.
├── pom.xml # build file
├── src
│ ├── main
│ │ ├── groovy # job builder and support classes
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
89. Project structure
.
├── pom.xml # build file
├── src
│ ├── main
│ │ ├── groovy # job builder and support classes
│ │ └── resources
│ │ ├── bin # common scripts (shell, batch, groovy etc.)
│ │ ├── jobs # DSL script files for jobs
│ │ └── views # DSL script files for views
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
90. Project structure
.
├── pom.xml # build file
├── src
│ ├── main
│ │ ├── groovy # job builder and support classes
│ │ └── resources
│ │ ├── bin # common scripts (shell, batch, groovy etc.)
│ │ ├── jobs # DSL script files for jobs
│ │ └── views # DSL script files for views
│ └── test
│ ├── groovy # specs for the job builders and their functionality
│ └── resources # script files for tests
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
91. Project structure
.
├── pom.xml # build file
├── src
│ ├── main
│ │ ├── groovy # job builder and support classes
│ │ └── resources
│ │ ├── bin # common scripts (shell, batch, groovy etc.)
│ │ ├── jobs # DSL script files for jobs
│ │ └── views # DSL script files for views
│ └── test
│ ├── groovy # specs for the job builders and their functionality
│ └── resources # script files for tests
└── target
└── debug-xml # output directory for all generated items during test
├── jobs # Useful to diff job changes
└── views
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
92. Project dependencies
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
<dependency>
<groupId>net.payback.ci</groupId>
<artifactId>dslbuilder</artifactId>
<version>${dslbuilder.version}</version>
</dependency>
<modules>
<module>dev-bi</module>
<module>dev-core</module>
<module>dev-performance</module>
<module>dev-portal</module>
[…]
<module>dev-vagrant</module>
</modules>
93. Project dependencies
Main project with common builders, functions
and tests. Has its own release cycle.
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
<dependency>
<groupId>net.payback.ci</groupId>
<artifactId>dslbuilder</artifactId>
<version>${dslbuilder.version}</version>
</dependency>
<modules>
<module>dev-bi</module>
<module>dev-core</module>
<module>dev-performance</module>
<module>dev-portal</module>
[…]
<module>dev-vagrant</module>
</modules>
94. Project dependencies
Main project with common builders, functions
and tests. Has its own release cycle.
Own modules for every team, department or
the same area of responsibility
An example on how to introduce Job DSL in a real life company
….…..................….......Intro Configuration as Code Test your codeThe next level
<dependency>
<groupId>net.payback.ci</groupId>
<artifactId>dslbuilder</artifactId>
<version>${dslbuilder.version}</version>
</dependency>
<modules>
<module>dev-bi</module>
<module>dev-core</module>
<module>dev-performance</module>
<module>dev-portal</module>
[…]
<module>dev-vagrant</module>
</modules>
95. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
….…..................….......Intro Configuration as Code Test your codeThe next level
96. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
….…..................….......Intro Configuration as Code Test your codeThe next level
97. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
98. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
99. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
100. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
101. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
102. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
103. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
104. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
105. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
106. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
107. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
108. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for
a group of jobs?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
109. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for
a group of jobs?
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
Refactor or search and replace
110. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for
a group of jobs?
• New scripting language
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
Refactor or search and replace
111. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for
a group of jobs?
• New scripting language
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
Refactor or search and replace
Simplified with custom builders
112. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for
a group of jobs?
• New scripting language
• New DSL reference to learn
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
Refactor or search and replace
Simplified with custom builders
113. Resolve ALL the issues
An example on how to introduce Job DSL in a real life company
http://knowyourmeme.com/memes/x-all-the-y
• What is this job doing?
• Is the job still in use?
• Who is responsible for this job?
• Why is it configured that way?
• What are the standard settings?
• Who changed what and when?
• How to change settings for
a group of jobs?
• New scripting language
• New DSL reference to learn
….…..................….......Intro Configuration as Code Test your codeThe next level
Minimum config, easy to read
Look at the commits
Everyone can read it, own modules
Simple methods for complex stuff
Set basics in job builders
Get all the benefits from VCS
Refactor or search and replace
Simplified with custom builders
Outstanding API viewer ;)
114. An example on how to introduce Job DSL in a real life company
How to make it foolproof
.........................….......Intro Configuration as Code Test your codeThe next level
115. How to make it foolproof
An example on how to introduce Job DSL in a real life company
People will do the same thing in the code, as they did before via the UI
.........................….......Intro Configuration as Code Test your codeThe next level
116. How to make it foolproof
• Copy & Paste of job builders
An example on how to introduce Job DSL in a real life company
People will do the same thing in the code, as they did before via the UI
.........................….......Intro Configuration as Code Test your codeThe next level
117. How to make it foolproof
• Copy & Paste of job builders
• Write jobs in pure dsl syntax, but forget about standards
An example on how to introduce Job DSL in a real life company
People will do the same thing in the code, as they did before via the UI
.........................….......Intro Configuration as Code Test your codeThe next level
118. How to make it foolproof
• Copy & Paste of job builders
• Write jobs in pure dsl syntax, but forget about standards
• Use anti-patterns in code, configuration will be unreadable again
An example on how to introduce Job DSL in a real life company
People will do the same thing in the code, as they did before via the UI
.........................….......Intro Configuration as Code Test your codeThe next level
119. How to make it foolproof
• Copy & Paste of job builders
• Write jobs in pure dsl syntax, but forget about standards
• Use anti-patterns in code, configuration will be unreadable again
An example on how to introduce Job DSL in a real life company
People will do the same thing in the code, as they did before via the UI
.........................….......Intro Configuration as Code Test your codeThe next level
WRITE TESTS
120. How to make it foolproof
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
121. Test Example from https://github.com/sheehan/job-dsl-gradle-example
An example on how to introduce Job DSL in a real life company
class JobScriptsSpec extends Specification {
@Unroll
void 'test script #file.name'(File file) {
given:
when:
then:
where:
[...]
}
...................................Intro Configuration as Code Test your codeThe next level
122. Test Example from https://github.com/sheehan/job-dsl-gradle-example
An example on how to introduce Job DSL in a real life company
class JobScriptsSpec extends Specification {
@Unroll
void 'test script #file.name'(File file) {
given:
JobManagement jm = Spy(MemoryJobManagement)
[...]
when:
then:
where:
[...]
}
...................................Intro Configuration as Code Test your codeThe next level
123. Test Example from https://github.com/sheehan/job-dsl-gradle-example
An example on how to introduce Job DSL in a real life company
class JobScriptsSpec extends Specification {
@Unroll
void 'test script #file.name'(File file) {
given:
JobManagement jm = Spy(MemoryJobManagement)
[...]
when:
DslScriptLoader(jm).runScript(file.text)
then:
where:
[...]
}
...................................Intro Configuration as Code Test your codeThe next level
124. Test Example from https://github.com/sheehan/job-dsl-gradle-example
An example on how to introduce Job DSL in a real life company
class JobScriptsSpec extends Specification {
@Unroll
void 'test script #file.name'(File file) {
given:
JobManagement jm = Spy(MemoryJobManagement)
[...]
when:
DslScriptLoader(jm).runScript(file.text)
then:
noExceptionThrown()
where:
[...]
}
...................................Intro Configuration as Code Test your codeThe next level
125. Test Example from https://github.com/sheehan/job-dsl-gradle-example
An example on how to introduce Job DSL in a real life company
class JobScriptsSpec extends Specification {
@Unroll
void 'test script #file.name'(File file) {
given:
JobManagement jm = Spy(MemoryJobManagement)
[...]
when:
DslScriptLoader(jm).runScript(file.text)
then:
noExceptionThrown()
where:
file << jobFiles
}
[...]
}
...................................Intro Configuration as Code Test your codeThe next level
126. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
........................…........Intro Configuration as Code Test your codeThe next level
127. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
128. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
// is any trigger set?
triggers
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
129. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
// is any trigger set?
triggers
// is trigger a timer trigger?
triggers.'hudson.triggers.TimerTrigger'
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
130. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
// is any trigger set?
triggers
// is trigger a timer trigger?
triggers.'hudson.triggers.TimerTrigger'
// trigger is NOT an scm trigger?
!triggers.'hudson.triggers.SCMTrigger'
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
131. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
// is any trigger set?
triggers
// is trigger a timer trigger?
triggers.'hudson.triggers.TimerTrigger'
// trigger is NOT an scm trigger?
!triggers.'hudson.triggers.SCMTrigger'
// has trigger a specific value?
triggers.text().equals('H * * * *')
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
132. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
// is any trigger set?
triggers
// is trigger a timer trigger?
triggers.'hudson.triggers.TimerTrigger'
// trigger is NOT an scm trigger?
!triggers.'hudson.triggers.SCMTrigger'
// has trigger a specific value?
triggers.text().equals('H * * * *')
// has timer trigger a specific value?
triggers.'hudson.triggers.TimerTrigger'.text().equals('H * * * *')
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
133. What can be tested?
An example on how to introduce Job DSL in a real life company
def 'this one has a timer trigger set, but no scm trigger'() {
setup:
Job job = new JobBuilder(jobParent, 'foo').make { cron(Cron.HOURLY) }
expect:
with(job.node) {
// is any trigger set?
triggers
// is trigger a timer trigger?
triggers.'hudson.triggers.TimerTrigger'
// trigger is NOT an scm trigger?
!triggers.'hudson.triggers.SCMTrigger'
// has trigger a specific value?
triggers.text().equals('H * * * *')
// has timer trigger a specific value?
triggers.'hudson.triggers.TimerTrigger'.text().equals('H * * * *')
// trigger has a tag with value timer trigger
triggers.get(0).value().get(0).name().equals('hudson.triggers.TimerTrigger')
}
}
........................…........Intro Configuration as Code Test your codeThe next level
<project>
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H * * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
</project>
134. Write tests for all job configurations
An example on how to introduce Job DSL in a real life company
def setupSpec() {
jobManagement = new MemoryJobManagement()
List<ScriptRequest> scriptRequests = []
ResourceHelper.getAllJobDslFiles().each { File script ->
URL scriptURL = new File(script.getPath()).toURI().toURL()
scriptRequests.add(new ScriptRequest(script.name, null, scriptURL))
}
new DslScriptLoader(jobManagement).runScripts(scriptRequests)
}
........................…........Intro Configuration as Code Test your codeThe next level
135. Write tests for all job configurations
An example on how to introduce Job DSL in a real life company
def setupSpec() {
jobManagement = new MemoryJobManagement()
List<ScriptRequest> scriptRequests = []
ResourceHelper.getAllJobDslFiles().each { File script ->
URL scriptURL = new File(script.getPath()).toURI().toURL()
scriptRequests.add(new ScriptRequest(script.name, null, scriptURL))
}
new DslScriptLoader(jobManagement).runScripts(scriptRequests)
}
@Unroll
def 'Always activate log rotation for "#config.key"'(Map.Entry<String, String> config) {
expect:
with(new XmlParser().parse(new StringReader(config.value))) {
!logRotator.text().isEmpty()
}
where:
script << jobManagement.savedConfigs
}
........................…........Intro Configuration as Code Test your codeThe next level
136. Overall Testing: Enforce scripting standards
@Unroll
def 'Turn off debug output for shell steps in "#config.key"'(Map.Entry<String, String> config) {
expect:
with(new XmlParser().parse(new StringReader(config.value))) {
}
where:
script << jobManagement.savedConfigs
}
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
137. Overall Testing: Enforce scripting standards
@Unroll
def 'Turn off debug output for shell steps in "#config.key"'(Map.Entry<String, String> config) {
expect:
with(new XmlParser().parse(new StringReader(config.value))) {
def scriptCommands = builders.get(0).children().findAll { buildStep ->
buildStep.name().equals('hudson.tasks.Shell')
}.collect { shellStep ->
shellStep.get('command').text()
}
}
where:
script << jobManagement.savedConfigs
}
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
138. Overall Testing: Enforce scripting standards
@Unroll
def 'Turn off debug output for shell steps in "#config.key"'(Map.Entry<String, String> config) {
expect:
with(new XmlParser().parse(new StringReader(config.value))) {
def scriptCommands = builders.get(0).children().findAll { buildStep ->
buildStep.name().equals('hudson.tasks.Shell')
}.collect { shellStep ->
shellStep.get('command').text()
}
// make sure every script has debug disabled by default
scriptCommands.findAll {
!it.startsWith('#!/bin/sh -en')
}.findAll {
!it.startsWith('@echo offn')
}.isEmpty()
}
where:
script << jobManagement.savedConfigs
}
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
139. Functional tests
def 'test functional stuff for your job builders'() {
when:
Job job = new JobBuilder(jobParent, 'foo').make {
parameters {
StringParam('IMPORTANT_PARAMETER', 'wrong!')
}
}
then:
thrown IllegalStateException('wrong parameter used!')
}
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
140. Some examples for the impact in the actual teams
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
141. Some examples for the impact in the actual teams
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
• Web development: Huge release process with a bunch of manual branches
-> Now it's a one-klick release
142. Some examples for the impact in the actual teams
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
• Web development: Huge release process with a bunch of manual branches
-> Now it's a one-klick release
• Business Intelligence: Hardly any automated processes via Jenkins
-> Now they automated everything
143. Some examples for the impact in the actual teams
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
• Web development: Huge release process with a bunch of manual branches
-> Now it's a one-klick release
• Business Intelligence: Hardly any automated processes via Jenkins
-> Now they automated everything
• Core development: Huge deploy job blob that no one understood
-> One-klick deploy jobs for every environment (350+ jobs)
144. Some examples for the impact in the actual teams
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level
• Web development: Huge release process with a bunch of manual branches
-> Now it's a one-klick release
• Business Intelligence: Hardly any automated processes via Jenkins
-> Now they automated everything
• Core development: Huge deploy job blob that no one understood
-> One-klick deploy jobs for every environment (350+ jobs)
Teams can work
autonomously
145. Benefits
• Refactor jobs without fear due to regression testing and debug output
• Reduced configuration mistakes due to functional testing
• No conflicts between distributed teams
• Easy change rollout
• Minimal configuration
• Maximal convention
An example on how to introduce Job DSL in a real life company
.........................….......Intro Configuration as Code Test your codeThe next level