1# NixOS module for Buildbot continous integration server. 2 3{ config, lib, pkgs, ... }: 4 5with lib; 6 7let 8 cfg = config.services.buildbot-master; 9 escapeStr = s: escape ["'"] s; 10 masterCfg = if cfg.masterCfg == null then pkgs.writeText "master.cfg" '' 11 from buildbot.plugins import * 12 factory = util.BuildFactory() 13 c = BuildmasterConfig = dict( 14 workers = [${concatStringsSep "," cfg.workers}], 15 protocols = { 'pb': {'port': ${toString cfg.bpPort} } }, 16 title = '${escapeStr cfg.title}', 17 titleURL = '${escapeStr cfg.titleUrl}', 18 buildbotURL = '${escapeStr cfg.buildbotUrl}', 19 db = dict(db_url='${escapeStr cfg.dbUrl}'), 20 www = dict(port=${toString cfg.port}), 21 change_source = [ ${concatStringsSep "," cfg.changeSource} ], 22 schedulers = [ ${concatStringsSep "," cfg.schedulers} ], 23 builders = [ ${concatStringsSep "," cfg.builders} ], 24 status = [ ${concatStringsSep "," cfg.status} ], 25 ) 26 for step in [ ${concatStringsSep "," cfg.factorySteps} ]: 27 factory.addStep(step) 28 29 ${cfg.extraConfig} 30 '' 31 else cfg.masterCfg; 32 33in { 34 options = { 35 services.buildbot-master = { 36 37 factorySteps = mkOption { 38 type = types.listOf types.str; 39 description = "Factory Steps"; 40 default = []; 41 example = [ 42 "steps.Git(repourl='git://github.com/buildbot/pyflakes.git', mode='incremental')" 43 "steps.ShellCommand(command=['trial', 'pyflakes'])" 44 ]; 45 }; 46 47 changeSource = mkOption { 48 type = types.listOf types.str; 49 description = "List of Change Sources."; 50 default = []; 51 example = [ 52 "changes.GitPoller('git://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)" 53 ]; 54 }; 55 56 enable = mkOption { 57 type = types.bool; 58 default = false; 59 description = "Whether to enable the Buildbot continuous integration server."; 60 }; 61 62 extraConfig = mkOption { 63 type = types.str; 64 description = "Extra configuration to append to master.cfg"; 65 default = "c['buildbotNetUsageData'] = None"; 66 }; 67 68 masterCfg = mkOption { 69 type = types.nullOr types.path; 70 description = "Optionally pass master.cfg path. Other options in this configuration will be ignored."; 71 default = null; 72 example = "/etc/nixos/buildbot/master.cfg"; 73 }; 74 75 schedulers = mkOption { 76 type = types.listOf types.str; 77 description = "List of Schedulers."; 78 default = [ 79 "schedulers.SingleBranchScheduler(name='all', change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=['runtests'])" 80 "schedulers.ForceScheduler(name='force',builderNames=['runtests'])" 81 ]; 82 }; 83 84 builders = mkOption { 85 type = types.listOf types.str; 86 description = "List of Builders."; 87 default = [ 88 "util.BuilderConfig(name='runtests',workernames=['example-worker'],factory=factory)" 89 ]; 90 }; 91 92 workers = mkOption { 93 type = types.listOf types.str; 94 description = "List of Workers."; 95 default = [ "worker.Worker('example-worker', 'pass')" ]; 96 }; 97 98 status = mkOption { 99 default = []; 100 type = types.listOf types.str; 101 description = "List of status notification endpoints."; 102 }; 103 104 user = mkOption { 105 default = "buildbot"; 106 type = types.str; 107 description = "User the buildbot server should execute under."; 108 }; 109 110 group = mkOption { 111 default = "buildbot"; 112 type = types.str; 113 description = "Primary group of buildbot user."; 114 }; 115 116 extraGroups = mkOption { 117 type = types.listOf types.str; 118 default = []; 119 description = "List of extra groups that the buildbot user should be a part of."; 120 }; 121 122 home = mkOption { 123 default = "/home/buildbot"; 124 type = types.path; 125 description = "Buildbot home directory."; 126 }; 127 128 buildbotDir = mkOption { 129 default = "${cfg.home}/master"; 130 type = types.path; 131 description = "Specifies the Buildbot directory."; 132 }; 133 134 bpPort = mkOption { 135 default = 9989; 136 type = types.int; 137 description = "Port where the master will listen to Buildbot Worker."; 138 }; 139 140 listenAddress = mkOption { 141 default = "0.0.0.0"; 142 type = types.str; 143 description = "Specifies the bind address on which the buildbot HTTP interface listens."; 144 }; 145 146 buildbotUrl = mkOption { 147 default = "http://localhost:8010/"; 148 type = types.str; 149 description = "Specifies the Buildbot URL."; 150 }; 151 152 title = mkOption { 153 default = "Buildbot"; 154 type = types.str; 155 description = "Specifies the Buildbot Title."; 156 }; 157 158 titleUrl = mkOption { 159 default = "Buildbot"; 160 type = types.str; 161 description = "Specifies the Buildbot TitleURL."; 162 }; 163 164 dbUrl = mkOption { 165 default = "sqlite:///state.sqlite"; 166 type = types.str; 167 description = "Specifies the database connection string."; 168 }; 169 170 port = mkOption { 171 default = 8010; 172 type = types.int; 173 description = "Specifies port number on which the buildbot HTTP interface listens."; 174 }; 175 176 package = mkOption { 177 type = types.package; 178 default = pkgs.buildbot-full; 179 defaultText = "pkgs.buildbot-full"; 180 description = "Package to use for buildbot."; 181 example = literalExample "pkgs.buildbot-full"; 182 }; 183 184 packages = mkOption { 185 default = with pkgs; [ python27Packages.twisted git ]; 186 example = literalExample "[ pkgs.git ]"; 187 type = types.listOf types.package; 188 description = "Packages to add to PATH for the buildbot process."; 189 }; 190 }; 191 }; 192 193 config = mkIf cfg.enable { 194 users.extraGroups = optional (cfg.group == "buildbot") { 195 name = "buildbot"; 196 }; 197 198 users.extraUsers = optional (cfg.user == "buildbot") { 199 name = "buildbot"; 200 description = "Buildbot User."; 201 isNormalUser = true; 202 createHome = true; 203 home = cfg.home; 204 group = cfg.group; 205 extraGroups = cfg.extraGroups; 206 useDefaultShell = true; 207 }; 208 209 systemd.services.buildbot-master = { 210 description = "Buildbot Continuous Integration Server."; 211 after = [ "network-online.target" ]; 212 wantedBy = [ "multi-user.target" ]; 213 path = cfg.packages; 214 215 preStart = '' 216 env > envvars 217 mkdir -vp ${cfg.buildbotDir} 218 ln -sfv ${masterCfg} ${cfg.buildbotDir}/master.cfg 219 rm -fv $cfg.buildbotDir}/buildbot.tac 220 ${cfg.package}/bin/buildbot create-master ${cfg.buildbotDir} 221 ''; 222 223 serviceConfig = { 224 Type = "simple"; 225 User = cfg.user; 226 Group = cfg.group; 227 WorkingDirectory = cfg.home; 228 ExecStart = "${cfg.package}/bin/buildbot start --nodaemon ${cfg.buildbotDir}"; 229 }; 230 231 }; 232 }; 233 234 meta.maintainers = with lib.maintainers; [ nand0p mic92 ]; 235 236}