1 # NixOS module for Buildbot continuous integration server.
10 cfg = config.services.buildbot-master;
11 opt = options.services.buildbot-master;
13 package = cfg.package.python.pkgs.toPythonModule cfg.package;
14 python = cfg.package.python;
16 escapeStr = lib.escape [ "'" ];
18 defaultMasterCfg = pkgs.writeText "master.cfg" ''
19 from buildbot.plugins import *
21 factory = util.BuildFactory()
22 c = BuildmasterConfig = dict(
23 workers = [${lib.concatStringsSep "," cfg.workers}],
24 protocols = { 'pb': {'port': ${toString cfg.pbPort} } },
25 title = '${escapeStr cfg.title}',
26 titleURL = '${escapeStr cfg.titleUrl}',
27 buildbotURL = '${escapeStr cfg.buildbotUrl}',
28 db = dict(db_url='${escapeStr cfg.dbUrl}'),
29 www = dict(port=${toString cfg.port}),
30 change_source = [ ${lib.concatStringsSep "," cfg.changeSource} ],
31 schedulers = [ ${lib.concatStringsSep "," cfg.schedulers} ],
32 builders = [ ${lib.concatStringsSep "," cfg.builders} ],
33 services = [ ${lib.concatStringsSep "," cfg.reporters} ],
34 configurators = [ ${lib.concatStringsSep "," cfg.configurators} ],
36 for step in [ ${lib.concatStringsSep "," cfg.factorySteps} ]:
42 tacFile = pkgs.writeText "buildbot-master.tac" ''
45 from twisted.application import service
46 from buildbot.master import BuildMaster
48 basedir = '${cfg.buildbotDir}'
50 configfile = '${cfg.masterCfg}'
52 # Default umask for server
55 # note: this line is matched against to check that this is a buildmaster
56 # directory; do not edit it.
57 application = service.Application('buildmaster')
59 m = BuildMaster(basedir, configfile, umask)
60 m.setServiceParent(application)
66 services.buildbot-master = {
68 factorySteps = lib.mkOption {
69 type = lib.types.listOf lib.types.str;
70 description = "Factory Steps";
73 "steps.Git(repourl='https://github.com/buildbot/pyflakes.git', mode='incremental')"
74 "steps.ShellCommand(command=['trial', 'pyflakes'])"
78 changeSource = lib.mkOption {
79 type = lib.types.listOf lib.types.str;
80 description = "List of Change Sources.";
83 "changes.GitPoller('https://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
87 configurators = lib.mkOption {
88 type = lib.types.listOf lib.types.str;
89 description = "Configurator Steps, see https://docs.buildbot.net/latest/manual/configuration/configurators.html";
92 "util.JanitorConfigurator(logHorizon=timedelta(weeks=4), hour=12, dayOfWeek=6)"
96 enable = lib.mkOption {
97 type = lib.types.bool;
99 description = "Whether to enable the Buildbot continuous integration server.";
102 extraConfig = lib.mkOption {
103 type = lib.types.lines;
104 description = "Extra configuration to append to master.cfg";
105 default = "c['buildbotNetUsageData'] = None";
108 extraImports = lib.mkOption {
109 type = lib.types.lines;
110 description = "Extra python imports to prepend to master.cfg";
112 example = "from buildbot.process.project import Project";
115 masterCfg = lib.mkOption {
116 type = lib.types.path;
117 description = "Optionally pass master.cfg path. Other options in this configuration will be ignored.";
118 default = defaultMasterCfg;
119 defaultText = lib.literalMD ''generated configuration file'';
120 example = "/etc/nixos/buildbot/master.cfg";
123 schedulers = lib.mkOption {
124 type = lib.types.listOf lib.types.str;
125 description = "List of Schedulers.";
127 "schedulers.SingleBranchScheduler(name='all', change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=['runtests'])"
128 "schedulers.ForceScheduler(name='force',builderNames=['runtests'])"
132 builders = lib.mkOption {
133 type = lib.types.listOf lib.types.str;
134 description = "List of Builders.";
136 "util.BuilderConfig(name='runtests',workernames=['example-worker'],factory=factory)"
140 workers = lib.mkOption {
141 type = lib.types.listOf lib.types.str;
142 description = "List of Workers.";
143 default = [ "worker.Worker('example-worker', 'pass')" ];
146 reporters = lib.mkOption {
148 type = lib.types.listOf lib.types.str;
149 description = "List of reporter objects used to present build status to various users.";
152 user = lib.mkOption {
153 default = "buildbot";
154 type = lib.types.str;
155 description = "User the buildbot server should execute under.";
158 group = lib.mkOption {
159 default = "buildbot";
160 type = lib.types.str;
161 description = "Primary group of buildbot user.";
164 extraGroups = lib.mkOption {
165 type = lib.types.listOf lib.types.str;
167 description = "List of extra groups that the buildbot user should be a part of.";
170 home = lib.mkOption {
171 default = "/home/buildbot";
172 type = lib.types.path;
173 description = "Buildbot home directory.";
176 buildbotDir = lib.mkOption {
177 default = "${cfg.home}/master";
178 defaultText = lib.literalExpression ''"''${config.${opt.home}}/master"'';
179 type = lib.types.path;
180 description = "Specifies the Buildbot directory.";
183 pbPort = lib.mkOption {
185 type = lib.types.either lib.types.str lib.types.int;
186 example = "'tcp:9990:interface=127.0.0.1'";
188 The buildmaster will listen on a TCP port of your choosing
189 for connections from workers.
190 It can also use this port for connections from remote Change Sources,
191 status clients, and debug tools.
192 This port should be visible to the outside world, and you’ll need to tell
193 your worker admins about your choice.
194 If put in (single) quotes, this can also be used as a connection string,
195 as defined in the [ConnectionStrings guide](https://twistedmatrix.com/documents/current/core/howto/endpoints.html).
199 listenAddress = lib.mkOption {
201 type = lib.types.str;
202 description = "Specifies the bind address on which the buildbot HTTP interface listens.";
205 buildbotUrl = lib.mkOption {
206 default = "http://localhost:8010/";
207 type = lib.types.str;
208 description = "Specifies the Buildbot URL.";
211 title = lib.mkOption {
212 default = "Buildbot";
213 type = lib.types.str;
214 description = "Specifies the Buildbot Title.";
217 titleUrl = lib.mkOption {
218 default = "Buildbot";
219 type = lib.types.str;
220 description = "Specifies the Buildbot TitleURL.";
223 dbUrl = lib.mkOption {
224 default = "sqlite:///state.sqlite";
225 type = lib.types.str;
226 description = "Specifies the database connection string.";
229 port = lib.mkOption {
231 type = lib.types.port;
232 description = "Specifies port number on which the buildbot HTTP interface listens.";
235 package = lib.mkPackageOption pkgs "buildbot-full" {
236 example = "buildbot";
239 packages = lib.mkOption {
240 default = [ pkgs.git ];
241 defaultText = lib.literalExpression "[ pkgs.git ]";
242 type = lib.types.listOf lib.types.package;
243 description = "Packages to add to PATH for the buildbot process.";
246 pythonPackages = lib.mkOption {
247 type = lib.types.functionTo (lib.types.listOf lib.types.package);
248 default = pythonPackages: with pythonPackages; [ ];
249 defaultText = lib.literalExpression "pythonPackages: with pythonPackages; [ ]";
250 description = "Packages to add the to the PYTHONPATH of the buildbot process.";
251 example = lib.literalExpression "pythonPackages: with pythonPackages; [ requests ]";
256 config = lib.mkIf cfg.enable {
257 users.groups = lib.optionalAttrs (cfg.group == "buildbot") {
261 users.users = lib.optionalAttrs (cfg.user == "buildbot") {
263 description = "Buildbot User.";
266 inherit (cfg) home group extraGroups;
267 useDefaultShell = true;
271 systemd.services.buildbot-master = {
272 description = "Buildbot Continuous Integration Server.";
273 after = [ "network.target" ];
274 wantedBy = [ "multi-user.target" ];
275 path = cfg.packages ++ cfg.pythonPackages python.pkgs;
276 environment.PYTHONPATH = "${
277 python.withPackages (self: cfg.pythonPackages self ++ [ package ])
278 }/${python.sitePackages}";
281 mkdir -vp "${cfg.buildbotDir}"
282 # Link the tac file so buildbot command line tools recognize the directory
283 ln -sf "${tacFile}" "${cfg.buildbotDir}/buildbot.tac"
284 ${cfg.package}/bin/buildbot create-master --db "${cfg.dbUrl}" "${cfg.buildbotDir}"
285 rm -f buildbot.tac.new master.cfg.sample
292 WorkingDirectory = cfg.home;
293 # NOTE: call twistd directly with stdout logging for systemd
294 ExecStart = "${python.pkgs.twisted}/bin/twistd -o --nodaemon --pidfile= --logfile - --python ${cfg.buildbotDir}/buildbot.tac";
295 # To reload on upgrade, set the following in your configuration:
296 # systemd.services.buildbot-master.reloadIfChanged = true;
298 "${pkgs.coreutils}/bin/ln -sf ${tacFile} ${cfg.buildbotDir}/buildbot.tac"
299 "${pkgs.coreutils}/bin/kill -HUP $MAINPID"
306 (lib.mkRenamedOptionModule
307 [ "services" "buildbot-master" "bpPort" ]
308 [ "services" "buildbot-master" "pbPort" ]
310 (lib.mkRemovedOptionModule [ "services" "buildbot-master" "status" ] ''
311 Since Buildbot 0.9.0, status targets are deprecated and ignored.
312 Review your configuration and migrate to reporters (available at services.buildbot-master.reporters).
316 meta.maintainers = lib.teams.buildbot.members;