Skip to content

Commit

Permalink
Fix #12: Add support for auto-generated DSL and extensions
Browse files Browse the repository at this point in the history
Add support for the auto-generated DSL [1] and Job DSL extensions [2].

This is implemented using the Jenkins test-harness to execute the Job DSL
scripts in a temporary Jenkins instance. This way the discovery of plugin
extension points works the same way as it does in a Job DSL seed job.

The list of plugins can be configured in the jenkinsPlugins configuration
in Gradle.

Also change the next version to 3.0.0 because this is a major change.

[1] https://github.com/jenkinsci/job-dsl-plugin/wiki/Automatically-Generated-DSL
[2] https://github.com/jenkinsci/job-dsl-plugin/wiki/Extending-the-DSL
  • Loading branch information
mnonnenmacher committed Jan 4, 2018
1 parent 03ac07d commit 3b1bed6
Show file tree
Hide file tree
Showing 31 changed files with 790 additions and 102 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## 2.2.0 (under development)
## 3.0.0 (under development)

- Add support for auto-generated DSL and Job DSL extensions by executing the Job DSL scripts in a local Jenkins
instance.

## 2.1.1 (2017-12-04)

Expand Down
16 changes: 16 additions & 0 deletions plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,28 @@ dependencies {
compile('org.jenkins-ci.plugins:job-dsl-core:1.66') {
exclude(module: 'groovy-all')
}
compile 'org.jenkins-ci.plugins:job-dsl:1.66@jar'
compile 'org.jenkins-ci:version-number:1.4'

compile('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2') {
exclude(module: 'groovy')
exclude(module: 'xercesImpl')
}

// Need to exclude XML parsers: https://issues.jenkins-ci.org/browse/JENKINS-35638
compile('org.jenkins-ci.main:jenkins-test-harness:2.32') {
exclude(module: 'org-netbeans-insane')
exclude(module: 'serializer')
exclude(module: 'xalan')
exclude(module: 'xercesImpl')
}

compile('org.jenkins-ci.main:jenkins-war:2.92') {
exclude(module: 'groovy-all')
exclude(module: 'slf4j-jdk14')
exclude(module: 'xalan')
}

testCompile('org.spockframework:spock-core:1.1-groovy-2.4') {
exclude(module: 'groovy-all')
}
Expand All @@ -74,6 +89,7 @@ dependencies {
exclude(module: 'slf4j-jdk14')
}

// Need to exclude transitive dependency because of: https://github.com/gradle/gradle/issues/3666
functionalTestCompile('org.jenkins-ci.main:jenkins-test-harness:2.32') {
exclude(module: 'org-netbeans-insane')
}
Expand Down
2 changes: 1 addition & 1 deletion plugin/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Maven configuration
maven.groupId=com.here.gradle.plugins
maven.artifactId=gradle-jenkins-jobdsl-plugin
maven.version=2.2.0-SNAPSHOT
maven.version=3.0.0-SNAPSHOT
# Set this flag to true for release builds.
maven.release=false
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.here.gradle.plugins.jobdsl
import com.here.gradle.plugins.jobdsl.tasks.GenerateXmlTask
import com.here.gradle.plugins.jobdsl.tasks.UpdateJenkinsTask
import org.gradle.api.Project
import org.gradle.api.tasks.Copy
import org.gradle.testfixtures.ProjectBuilder
import spock.lang.Specification

Expand All @@ -17,12 +18,21 @@ class JobDslPluginTest extends Specification {
project = ProjectBuilder.builder().build()
}

def 'resolveJenkinsPlugins task is created'() {
when:
project.pluginManager.apply('com.here.jobdsl')

then:
project.tasks.resolveJenkinsPlugins instanceof Copy
}

def 'dslGenerateXml task is created'() {
when:
project.pluginManager.apply('com.here.jobdsl')

then:
project.tasks.dslGenerateXml instanceof GenerateXmlTask
project.tasks.dslUpdateJenkins.dependsOn.contains('resolveJenkinsPlugins')
}

def 'dslUpdateJenkins task is created'() {
Expand All @@ -31,6 +41,7 @@ class JobDslPluginTest extends Specification {

then:
project.tasks.dslUpdateJenkins instanceof UpdateJenkinsTask
project.tasks.dslUpdateJenkins.dependsOn.contains('resolveJenkinsPlugins')
}

def 'groovy plugin is applied'() {
Expand All @@ -41,6 +52,15 @@ class JobDslPluginTest extends Specification {
project.plugins.hasPlugin('groovy')
}

def 'required repositories are added'() {
when:
project.pluginManager.apply('com.here.jobdsl')

then:
project.repositories.find { it.url.toString() == 'https://repo.jenkins-ci.org/releases/' }
project.repositories.find { it.url.toString() == 'https://repo1.maven.org/maven2/' }
}

def 'jobdsl source set is created'() {
when:
project.pluginManager.apply('com.here.jobdsl')
Expand All @@ -49,6 +69,14 @@ class JobDslPluginTest extends Specification {
project.sourceSets.findByName('jobdsl')
}

def 'jenkinsPlugins configuration is created'() {
when:
project.pluginManager.apply('com.here.jobdsl')

then:
project.configurations.findByName('jenkinsPlugins')
}

def 'jobdsl extension is created'() {
when:
project.pluginManager.apply('com.here.jobdsl')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class GenerateXmlTest extends AbstractTaskTest {

when:
def result = gradleRunner
.withArguments('dslGenerateXml', '--filter=.*unfiltered.*')
.withArguments('dslGenerateXml', '--filter=(folder|.*unfiltered.*)')
.build()

then:
Expand All @@ -130,7 +130,7 @@ class GenerateXmlTest extends AbstractTaskTest {

when:
def result = gradleRunner
.withArguments('dslGenerateXml', '--filter=.*unfiltered.*')
.withArguments('dslGenerateXml', '--filter=(folder|.*unfiltered.*)')
.build()

then:
Expand All @@ -142,23 +142,6 @@ class GenerateXmlTest extends AbstractTaskTest {
!new File(testProjectDir.root, 'build/jobdsl/xml/folder/view-filtered.xml').file
}

def 'can create job in filtered folder'() {
given:
buildFile << readBuildGradle('generateXml/build.gradle')
copyResourceToTestDir('generateXml/job-in-filtered-folder.groovy')

when:
def result = gradleRunner
.withArguments('dslGenerateXml', '--filter=.*job.*')
.build()

then:
result.task(':dslGenerateXml').outcome == TaskOutcome.SUCCESS

!new File(testProjectDir.root, 'build/jobdsl/xml/folder.xml').file
new File(testProjectDir.root, 'build/jobdsl/xml/folder/job.xml').file
}

def 'global configuration is available in DSL scripts'() {
given:
buildFile << readBuildGradle('generateXml/build-with-configuration.gradle')
Expand Down Expand Up @@ -288,4 +271,77 @@ class GenerateXmlTest extends AbstractTaskTest {
XMLUnit.compareXML(expectedText, actualText).identical()
}

def 'job with generated DSL is generated correctly'() {
given:
buildFile << readBuildGradle('generateXml/build-with-generated-dsl.gradle')
copyResourceToTestDir('generateXml/job-with-generated-dsl.groovy')

when:
def result = gradleRunner
.withArguments('dslGenerateXml')
.build()

then:
result.task(':dslGenerateXml').outcome == TaskOutcome.SUCCESS

def generatedFile = new File(testProjectDir.root, 'build/jobdsl/xml/job.xml')
generatedFile.file
def actualText = generatedFile.getText('UTF-8')
def expectedText = readResource('generateXml/job-with-generated-dsl.xml')
XMLUnit.compareXML(expectedText, actualText).identical()
}

def 'task fails when plugin for generated DSL is missing'() {
given:
buildFile << readBuildGradle('generateXml/build.gradle')
copyResourceToTestDir('generateXml/job-with-generated-dsl.groovy')

when:
def result = gradleRunner
.withArguments('dslGenerateXml')
.buildAndFail()

then:
result.task(':dslGenerateXml').outcome == TaskOutcome.FAILED
result.output.contains('No signature of method: javaposse.jobdsl.dsl.helpers.ScmContext.cvsscm() is ' +
'applicable for argument types')
}

def 'job with Job DSL extension is generated correctly'() {
given:
buildFile << readBuildGradle('generateXml/build-with-jobdsl-extension.gradle')
copyResourceToTestDir('generateXml/job-with-job-dsl-extension.groovy')

when:
def result = gradleRunner
.withArguments('dslGenerateXml')
.build()

then:
result.task(':dslGenerateXml').outcome == TaskOutcome.SUCCESS

def generatedFile = new File(testProjectDir.root, 'build/jobdsl/xml/job.xml')
generatedFile.file
def actualText = generatedFile.getText('UTF-8')
def expectedText = readResource('generateXml/job-with-job-dsl-extension.xml')
XMLUnit.compareXML(expectedText, actualText).identical()
}

def 'task fails when plugin for Job DSL extension is missing'() {
given:
buildFile << readBuildGradle('generateXml/build.gradle')
copyResourceToTestDir('generateXml/job-with-job-dsl-extension.groovy')

when:
def result = gradleRunner
.withArguments('dslGenerateXml')
.buildAndFail()

then:
result.task(':dslGenerateXml').outcome == TaskOutcome.FAILED
result.output.contains(
'No signature of method: javaposse.jobdsl.dsl.helpers.publisher.PublisherContext.jgivenReports() is ' +
'applicable for argument types')
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ class UpdateJenkinsTest extends AbstractTaskTest {

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.SUCCESS
gradleSectionOutput(result.output, 'Deprecated plugins:') == [ 'htmlpublisher' ]
gradleSectionOutput(result.output, 'Deprecated plugins:') == ['htmlpublisher']
}

def 'missing plugins are reported'() {
Expand All @@ -345,7 +345,7 @@ class UpdateJenkinsTest extends AbstractTaskTest {

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.SUCCESS
gradleSectionOutput(result.output, 'Missing plugins:') == [ 'gradle', 'timestamper' ]
gradleSectionOutput(result.output, 'Missing plugins:') == ['gradle', 'timestamper']
}

@WithPlugin('gradle-1.22.hpi')
Expand All @@ -359,7 +359,7 @@ class UpdateJenkinsTest extends AbstractTaskTest {

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.SUCCESS
gradleSectionOutput(result.output, 'Outdated plugins:') == [ 'gradle' ]
gradleSectionOutput(result.output, 'Outdated plugins:') == ['gradle']
}

def 'groovy postbuild step with UTF-8 characters is uploaded correctly'() {
Expand All @@ -380,4 +380,79 @@ class UpdateJenkinsTest extends AbstractTaskTest {
).identical()
}

def 'job with generated DSL is uploaded correctly'() {
given:
buildFile << readBuildGradle('updateJenkins/build-with-generated-dsl.gradle')
copyResourceToTestDir('updateJenkins/job-with-generated-dsl.groovy')

when:
def result = gradleRunner
.withArguments('dslUpdateJenkins', jenkinsUrlParam())
.build()

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.SUCCESS

Item item = jenkinsRule.jenkins.getItemByFullName('job')
item instanceof FreeStyleProject
XMLUnit.compareXML(
readResource('updateJenkins/job-with-generated-dsl.xml'),
item.configFile.asString()
).identical()
}

def 'task fails when plugin for generated DSL is missing'() {
given:
buildFile << readBuildGradle('updateJenkins/build.gradle')
copyResourceToTestDir('updateJenkins/job-with-generated-dsl.groovy')

when:
def result = gradleRunner
.withArguments('dslUpdateJenkins', jenkinsUrlParam())
.buildAndFail()

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.FAILED
result.output.contains('No signature of method: javaposse.jobdsl.dsl.helpers.ScmContext.cvsscm() is ' +
'applicable for argument types')
}

def 'job with Job DSL extension is uploaded correctly'() {
given:
buildFile << readBuildGradle('updateJenkins/build-with-jobdsl-extension.gradle')
copyResourceToTestDir('updateJenkins/job-with-job-dsl-extension.groovy')

when:
def result = gradleRunner
.withArguments('dslUpdateJenkins', jenkinsUrlParam())
.build()

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.SUCCESS

Item item = jenkinsRule.jenkins.getItemByFullName('job')
item instanceof FreeStyleProject
XMLUnit.compareXML(
readResource('updateJenkins/job-with-job-dsl-extension.xml'),
item.configFile.asString()
).identical()
}

def 'task fails when plugin for Job DSL extension is missing'() {
given:
buildFile << readBuildGradle('updateJenkins/build.gradle')
copyResourceToTestDir('updateJenkins/job-with-job-dsl-extension.groovy')

when:
def result = gradleRunner
.withArguments('dslUpdateJenkins', jenkinsUrlParam())
.buildAndFail()

then:
result.task(':dslUpdateJenkins').outcome == TaskOutcome.FAILED
result.output.contains(
'No signature of method: javaposse.jobdsl.dsl.helpers.publisher.PublisherContext.jgivenReports() is ' +
'applicable for argument types')
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
buildscript {
dependencies {
classpath files(CLASSPATH_STRING)
}
}

apply plugin: 'com.here.jobdsl'

dependencies {
compile localGroovy()

jenkinsPlugins 'org.jenkins-ci.plugins:cloudbees-folder:6.2.1'
jenkinsPlugins 'org.jenkins-ci.plugins:cvs:2.13'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
buildscript {
dependencies {
classpath files(CLASSPATH_STRING)
}
}

apply plugin: 'com.here.jobdsl'

dependencies {
compile localGroovy()

jenkinsPlugins 'org.jenkins-ci.plugins:cloudbees-folder:6.2.1'
jenkinsPlugins 'org.jenkins-ci.plugins:jgiven:0.15.1'
}
2 changes: 2 additions & 0 deletions plugin/src/functionalTest/resources/generateXml/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ apply plugin: 'com.here.jobdsl'

dependencies {
compile localGroovy()

jenkinsPlugins 'org.jenkins-ci.plugins:cloudbees-folder:6.2.1'
}
Loading

0 comments on commit 3b1bed6

Please sign in to comment.