pipeline {
stages {
stage('Build') {
when { branch "develop || master || feature"} // no the real syntax, i know
steps { /* do some build stuff */ }
}
stage('Scan') {
when { branch "master"}
steps { /* run static code analysis or other code scanning */}
}
stage('Pull Request Build') {
when { branch "PR-*"}
steps { /* do a merge build stuff */ }
}
stage('Dev Deploy') {
when { branch "develop || master"}
steps { /* deploy to dev */ }
}
stage('Pull Request Deploy') {
when { branch "PR-*"}
steps { /* deploy to special PR sandbox */}
}
}
}
In this simple example, the following will happen, but it is extremely hard to follow.
Feature -> Build
Master -> Build, Scan, Dev Deploy
Develop -> Build, Dev Deploy
Pull Request -> Pull Request Build, Pull Request Deploy
I would suggest we allow the when to be placed at the pipeline level somehow.args
pipeline('master') { // Just for naming
when { branch "master" }
stages {
stage('Build'){
steps { /* do some build stuff */ }
}
stage('Scan'){
steps { /* run static code analysis or other code scanning */}
}
stage('Dev Deploy'){
steps { /* deploy to dev */ }
}
}
}
pipeline('develop') { // Just for naming
when { branch "develop" }
stages {
stage('Build'){
steps { /* do some build stuff */ }
}
stage('Dev Deploy'){
steps { /* deploy to dev */ }
}
}
}
pipeline('pull request') { // Just for naming
when { branch "PR-*" }
stages {
stage('Pull Request Build') {
steps { /* do a merge build stuff */ }
}
stage('Pull Request Deploy') {
steps { /* deploy to special PR sandbox */}
}
}
}
pipeline('feature') { // Just for naming
when { branch != "master || PR-* || develop" } // just do a build for any 'other' branches, which would then include developer feature branches
stages {
stage('Build') {
steps { /* do some build stuff */ }
}
}
}
That, to me, is much cleaner. It is very easy to see exactly what each pipeline is doing.
This brings one downside. The stage is repeated.
stage('Build') and stage('Dev Deploy') are the same impl, but I have to write them 2 times.
I could create a global library, but then that has 2 other downsides. It is no longer declarative syntax in the global library, the global library is loaded external. I have to now go to a whole other file to see that implementation.
To keep things DRY I would also like to then see the stages treated as a definition and and implementation.
Define the stages external to the pipeline, but pull them into each pipeline.
This can optionally be done (like you'll see on the Pull Request stages).
Here is what I believe the combination of the two would look like:
pipeline('master') { // Just for naming
when { branch "master" }
stages {
stage('Build')
stage('Scan')
stage('Dev Deploy')
}
}
pipeline('develop') { // Just for naming
when { branch "develop" }
stages {
stage('Build')
stage('Dev Deploy')
}
}
pipeline('pull request') { // Just for naming
when { branch "PR-*" }
stages {
stage('Pull Request Build') {
steps { /* do a merge build stuff */ }
}
stage('Pull Request Deploy') {
steps { /* deploy to special PR sandbox */}
}
}
}
pipeline('feature') { // Just for naming
when { branch != "master || PR-* || develop" } // just do a build for any 'other' branches, which would then include developer feature branches
stages {
stage('Build')
}
}
/* Stage definitions below */
stage('Build'){
steps { /* do some build stuff */ }
}
stage('Scan'){
steps { /* run static code analysis or other code scanning */}
}
stage('Dev Deploy'){
steps { /* deploy to dev */ }
}
Is there a way to do this with the current declarative syntax?
If not, what is the best way to get this into the declarative syntax? Open jira enhancement requests?
What we've resorted to in the mean time (which still doesn't solve the DRY part) is to have a Jenkinsfile that does the if logic and then loads a specific pipeline (which has its own demons because the load evals the file immediately and is holding onto a heavyweight executor the whole time).
if (env.BRANCH_NAME.startsWith("develop")) {
load 'develop-pipeline.groovy'
} else if (env.BRANCH_NAME.startsWith("master")) {
load 'master-pipeline.groovy'
} else if (env.BRANCH_NAME.startsWith("PR-")) {
load 'pull-request-pipeline.groovy'
} else {
load 'feature-pipeline.groovy'
}
Thanks,
Ken