rule jenkins with configuration as code - cloudbees · rule jenkins with configuration as code...
TRANSCRIPT
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 code The 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 code The next level
4
Christian Rasp / [email protected] / @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 code The 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 code The 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 code The 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 code The next level
8 ….….. ............... ..... ...... An example on how to introduce Job DSL in a real life company
Intro Configuration as Code Test your code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The next level
18
Possible solutions
An example on how to introduce Job DSL in a real life company ….….. ............... ..... ...... Intro Configuration as Code Test your code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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('[email protected]') sendMail('[email protected]') }
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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('[email protected]') sendMail('[email protected]') }
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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('[email protected]') sendMail('[email protected]') }
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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('[email protected]') sendMail('[email protected]') }
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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('[email protected]') sendMail('[email protected]') }
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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('[email protected]') sendMail('[email protected]') }
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The next level
92
Project dependencies
An example on how to introduce Job DSL in a real life company ….….. ............... .…. ...... Intro Configuration as Code Test your code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 -e\n') }.findAll { !it.startsWith('@echo off\n') }.isEmpty() } where: script << jobManagement.savedConfigs }
An example on how to introduce Job DSL in a real life company ......... ............... .…. ...... Intro Configuration as Code Test your code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The 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 code The next level
146
THANK YOU!
PAYBACK GmbH
Christian rasp
Software Developer DevOps
Theresienhöhe 12
80339 München
Phone +49 (0) 89 997 41 – 1637
PAYBACK.net | PAYBACK.de