TL;DR up front:
*As a user, I want to have a pipeline that performs specific pipeline
stages based on the branch. Recommendation: Put the when{} condition
outside the pipeline{} tag.*
*As a user, I want to declare my stages but have the implementation be
separate so that I can reuse them in multiple pipelines*.
Currently the Declarative syntax has the ability to perform a stage
conditionally using 'when' but not a whole pipeline.
This leads to making the pipeline fairly inflexible and much harder to read
thru.
Take for example:
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
--
You received this message because you are subscribed to the Google Groups
"Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/jenkinsci-users/7b89a538-0b3d-4716-9308-cb1f2dfef2fb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.