Rule Jenkins with Configuration as Code - CloudBees · Rule Jenkins with Configuration as Code...

146
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

Transcript of Rule Jenkins with Configuration as Code - CloudBees · Rule Jenkins with Configuration as Code...

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

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

[email protected]

PAYBACK.net | PAYBACK.de