Buildbot调度器级别过滤构建器时遇配置错误求助
Buildbot自定义BuilderConfig类引发的配置错误及解决方法
问题背景
作为Buildbot新手,希望在调度器级别过滤构建器,避免默认触发所有关联构建。尝试通过继承util.BuilderConfig类创建Builder_A、Builder_B自定义类,重写build方法实现过滤,代码如下:
from buildbot.plugins import * c = BuildmasterConfig = {} c['workers'] = [worker.Worker("example-worker", "pass"), worker.Worker("example-worker1", "pass")] class Builder_A(util.BuilderConfig): name = "runtests" workernames = ["example-worker"] factory = util.BuildFactory() factory.addStep(steps.ShellCommand(command=["echo", "all"])) def build(self, request): if request.source.changes: for change in request.source.changes: if not change.files or all(file.endswith('.c') or file.endswith('.h') for file in change.files): return super().build(request) return None else: return None class Builder_B(util.BuilderConfig): name = "runtests1" workernames = ["example-worker1"] factory = util.BuildFactory() factory.addStep(steps.ShellCommand(command=["echo", "Source code"])) def build(self, request): if request.source.changes: for change in request.source.changes: if not change.files or all(file.endswith('.py') for file in change.files): return super().build(request) return None else: return None c['protocols'] = {'pb': {'port': 9989}} c['change_source'] = [] c['change_source'].append(changes.GitPoller( 'https://github.com/hello/Sample_Project.git', workdir='gitpoller-workdir', branch='master', pollInterval=30)) c['builders'] = [Builder_A(), Builder_B()] c['schedulers'] = [] c['schedulers'].append(schedulers.SingleBranchScheduler( name="all", change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=["runtests","runtests1"])) c['schedulers'].append(schedulers.ForceScheduler( name="force", builderNames=["runtests"])) c['services'] = [] c['title'] = "Hello World CI" c['titleURL'] = "https://buildbot.github.io/hello-world/" c['buildbotURL'] = "http://10.20.212.19:8010/" c['www'] = dict(port=8010, plugins=dict(waterfall_view={}, console_view={}, grid_view={})) c['db'] = { 'db_url' : "sqlite:///state.sqlite", }
出现的配置错误
Configuration Errors: builder's name is required builder '<unknown>' has no factory builder '<unknown>': at least one workername is required builder's name is required builder '<unknown>' has no factory builder '<unknown>': at least one workername is required builder(s) <unknown> have no schedulers to drive them Unknown builder 'runtests' in scheduler 'all' Unknown builder 'runtests1' in scheduler 'all' Unknown builder 'runtests' in scheduler 'force' duplicate builder name '<unknown>' duplicate builder builddir '_unknown_'
使用环境:Buildbot 1.1.1-3ubuntu5,Twisted 17.9.0,Ubuntu 18.04
错误原因分析
- BuilderConfig属性初始化方式错误:
util.BuilderConfig的核心属性(如name、workernames、factory)需要通过构造函数参数传递,而非类属性定义。直接在子类中定义类属性,父类构造函数无法读取这些属性,导致实例化后关键配置未初始化,Buildbot识别不出构建器的基本信息。 - 重写
build方法的思路错误:BuilderConfig的build方法并非用于过滤构建请求的官方入口,该方法不支持通过返回None跳过构建,正确的过滤逻辑应通过调度器change_filter或构建器buildFilter实现。
解决方法
方案1:构建器级别过滤(使用原生BuilderConfig+buildFilter)
无需继承BuilderConfig,直接创建实例,通过buildFilter为每个构建器添加自定义过滤逻辑:
from buildbot.plugins import * c = BuildmasterConfig = {} c['workers'] = [worker.Worker("example-worker", "pass"), worker.Worker("example-worker1", "pass")] # 定义构建工厂 factory_a = util.BuildFactory() factory_a.addStep(steps.ShellCommand(command=["echo", "all"])) factory_b = util.BuildFactory() factory_b.addStep(steps.ShellCommand(command=["echo", "Source code"])) # 自定义构建过滤函数 def filter_c_h_changes(request): if not request.source.changes: return False for change in request.source.changes: if not change.files or all(file.endswith('.c') or file.endswith('.h') for file in change.files): return True return False def filter_py_changes(request): if not request.source.changes: return False for change in request.source.changes: if not change.files or all(file.endswith('.py') for file in change.files): return True return False # 创建构建器实例 c['builders'] = [ util.BuilderConfig( name="runtests", workernames=["example-worker"], factory=factory_a, buildFilter=filter_c_h_changes ), util.BuilderConfig( name="runtests1", workernames=["example-worker1"], factory=factory_b, buildFilter=filter_py_changes ) ] # 其余配置保持不变 c['protocols'] = {'pb': {'port': 9989}} c['change_source'] = [] c['change_source'].append(changes.GitPoller( 'https://github.com/hello/Sample_Project.git', workdir='gitpoller-workdir', branch='master', pollInterval=30)) c['schedulers'] = [] c['schedulers'].append(schedulers.SingleBranchScheduler( name="all", change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=["runtests","runtests1"])) c['schedulers'].append(schedulers.ForceScheduler( name="force", builderNames=["runtests"])) c['services'] = [] c['title'] = "Hello World CI" c['titleURL'] = "https://buildbot.github.io/hello-world/" c['buildbotURL'] = "http://10.20.212.19:8010/" c['www'] = dict(port=8010, plugins=dict(waterfall_view={}, console_view={}, grid_view={})) c['db'] = { 'db_url' : "sqlite:///state.sqlite", }
方案2:调度器级别过滤(为不同构建器配置专属调度器)
在调度器层面控制触发逻辑,为每个构建器设置匹配对应文件类型的change_filter:
from buildbot.plugins import * c = BuildmasterConfig = {} c['workers'] = [worker.Worker("example-worker", "pass"), worker.Worker("example-worker1", "pass")] # 定义构建工厂 factory_a = util.BuildFactory() factory_a.addStep(steps.ShellCommand(command=["echo", "all"])) factory_b = util.BuildFactory() factory_b.addStep(steps.ShellCommand(command=["echo", "Source code"])) # 创建构建器实例 c['builders'] = [ util.BuilderConfig( name="runtests", workernames=["example-worker"], factory=factory_a ), util.BuilderConfig( name="runtests1", workernames=["example-worker1"], factory=factory_b ) ] # 自定义变更过滤函数 def c_h_filter(change): if not change.files: return True return all(file.endswith('.c') or file.endswith('.h') for file in change.files) def py_filter(change): if not change.files: return True return all(file.endswith('.py') for file in change.files) # 配置对应调度器 c['protocols'] = {'pb': {'port': 9989}} c['change_source'] = [] c['change_source'].append(changes.GitPoller( 'https://github.com/hello/Sample_Project.git', workdir='gitpoller-workdir', branch='master', pollInterval=30)) c['schedulers'] = [] # 匹配C/H文件变更的调度器 c['schedulers'].append(schedulers.SingleBranchScheduler( name="c_h_scheduler", change_filter=util.ChangeFilter(branch='master', filter_fn=c_h_filter), treeStableTimer=None, builderNames=["runtests"])) # 匹配Python文件变更的调度器 c['schedulers'].append(schedulers.SingleBranchScheduler( name="py_scheduler", change_filter=util.ChangeFilter(branch='master', filter_fn=py_filter), treeStableTimer=None, builderNames=["runtests1"])) c['schedulers'].append(schedulers.ForceScheduler( name="force", builderNames=["runtests"])) c['services'] = [] c['title'] = "Hello World CI" c['titleURL'] = "https://buildbot.github.io/hello-world/" c['buildbotURL'] = "http://10.20.212.19:8010/" c['www'] = dict(port=8010, plugins=dict(waterfall_view={}, console_view={}, grid_view={})) c['db'] = { 'db_url' : "sqlite:///state.sqlite", }
关键说明
- BuilderConfig正确用法:必须通过构造函数参数传递
name、workernames、factory等核心配置,不能用类属性替代。 - 过滤逻辑官方入口:优先使用
buildFilter(构建器级别)或change_filter(调度器级别)实现过滤,这是Buildbot官方推荐的标准方式。
内容的提问来源于stack exchange,提问作者vam
相关产品推荐
相关产品推荐

