最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

continuous integration - Jenkins multibranch pipelines: how to workaround missing parameters on first run - Stack Overflow

programmeradmin1浏览0评论

Story

I've got multiple multibranch pipelines defined in code using job-dsl plugin (actually with yaml files translated in groovy to job-dsl) and each one of them have some parameters (both bool and string) needed during execution. My issue is that currently those params are defined within declarative pipeline jenkinsfiles, so before first run on each branch jennkins does not know about them, so "build with parameters" button is not visible in GUI and also triggering those builds from another build using parameters fail. So after new branch is created we have to manually trigger all pipelines and all of them fail for that first build.

How I can worakround this? I've found this as opened issues for years now: & so I'm not counting on fix on jenkins side.

Failed solutions

I figured out 2 possible solutions:

  1. make jenkins always tirgger first job on new branch that will fail but will read jenkinsfile and update parameters - it's not grat since it will spam with job failed emails and red jobs in general. Another question is how to configure it given I have jobs that are triggered from other jobs, so i don't want them to run for all commits, just for that first time

  2. Pass information about parameters in job-dsl instead of (or in addidtion to) jenkinsfile - this is what I've done for "normal" pipline jobs, but I don't know how (or if possible at all) to do it for multibranch pipelines

MRE

jenkinsfile

At least 2 MBP jobs with jankinsfile like that:

pipeline {
    agent any
    parameters {
        string description: 'Product version', name: 'product_version', trim: true
        booleanParam description: 'Force trigger of downstream pipeline', name: 'force_downstream_trigger' // default: false
    }
    stages {
       stage ('Validate Parameters') {
            when {
                expression { return params.product_version?.isEmpty() }
            }
            steps {
                error 'Parameter "product_version" is empty'
            }
        }
        stage ('do stuff') {
            steps {
                // ...
            }
        }
        stage ('Trigger another pipe') {
            when {
                anyOf {
                    branch comparator: 'REGEXP', pattern: 'master'
                    expression { params.force_downstream_trigger }
                }
            }
                        steps {
                            build wait: false, job: "job2",
                                parameters: [
                                    string(name: 'product_version', value: product_version)
                                ]
                        }
        }
        
    }
}

job-dsl

Those pipeline in my case are generated by job seed using job-dsl plugin and:

jobs.yaml

defaults: &defaults
  credentials: gitlab_srv_acc
  filter_branch_regex: ^master$
  trigger_branch_regex: 
  fetch_tags: false
  run_for_mrs: true
  origin_merge_request_strategy: merge_with_target
  jenkinsfile_path: Jenkinsfile
  
jobs:
    job1: 
        <<: *defaults
        description: first one
    
    job2: 
        <<: *defaults
        description : second one

jobs.groovy:

@Grab('.yaml:snakeyaml:2.2')
import .yaml.snakeyaml.LoaderOptions;
import .yaml.snakeyaml.Yaml

def dl_parse_yaml(filename) {
    LoaderOptions options = new LoaderOptions()
    options.setMaxAliasesForCollections(100)
    Yaml yaml_parser = new Yaml(options)
    return yaml_parser.load(readFileFromWorkspace(filename))
}

def config = dl_parse_yaml("${WORKSPACE}/jenkins/jobs/universal_docking/hsw_multibranch.yaml")

config.jobs.each { job_name, job_props ->
    multibranchPipelineJob(job_name){
        displayName(job_name)
        description(job_props.description)
        factory{
            workflowBranchProjectFactory{
                scriptPath(job_props.jenkinsfile_path)
            }
        }
        branchSources{
            branchSource{
                source{
                    gitLabSCMSource {
                        id("${job_name}")
                        serverName('my gitlab url')
                        projectOwner('owner')
                        projectPath('group/project')
                        credentialsId('gitlab_acc')
                        traits{                            
                            gitLabBranchDiscovery{
                                strategyId(3) // discover all branches
                            }
                            if (job_props.run_for_mrs) {
                                originMergeRequestDiscoveryTrait {
                                    def merge_request_discovery_strategy = [
                                        "merge_with_target": 1,
                                        "build_mr_head": 2,
                                        "build_both_target_merge_and_head": 3
                                    ]
                                    strategyId(merge_request_discovery_strategy[job_props.origin_merge_request_strategy])
                                }
                            }
                            pruneStaleBranchTrait()
                            pruneStaleTagTrait()
                            headRegexFilter {
                                regex(job_props.filter_branch_regex)
                            }
                            buildStatusNameCustomPart {
                                buildStatusNameCustomPart("${job_name}")
                                // Overwrites the build status name including the jenkinsci default part.
                                // Instead of 'jenkinsci/custom/branch' just 'custom/branch'.
                                buildStatusNameOverwrite(true)
                            }
                        }
                    }
                }
                strategy{
                    allBranchesSame{
                        props{
                            suppressAutomaticTriggering{
                                strategy('NONE')
                                triggeredBranchesRegex(job_props.trigger_branch_regex)
                            }
                        }
                    }
                }
            }
        }
        triggers {
            periodicFolderTrigger {
                interval("24h")
            }
        }
        orphanedItemStrategy {
            discardOldItems {
                daysToKeep(1)
                numToKeep(3)
            }
        }
    }
}

But the same issue can be reproduced by configuring MBPs by hand and making it not run by default on branch creation / scm change.

Steps to reproduce:

  1. create new branch -> job1 and job2 does not run and does not have "build with parameters" button
  2. build job1 -> it's failing due to misising parameter but "build with parameters" appears
  3. build job1 giving it parameter value -> it works, triggers job2 which fail due to missing parameter

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论