J'avais besoin de configurer le processus de construction et de livraison sur le site de paquets logiciels depuis un dépôt Git. Ayant vu, il n'y a pas si longtemps, un article ici sur Habr concernant buildbot (lien à la fin), j'ai décidé d'essayer et de l'appliquer pour cela.
Puisque buildbot est un système distribué, il serait logique de créer un hôte de construction distinct pour chaque architecture et système d'exploitation. Dans notre cas, ce seront des conteneurs LXC (pour Linux) et qemu (pour Windows) :
- vm-srv-build1 — centos 7, ici sera le master buildbot et l'un des workers
- vm-srv-build2 — debian 10, pour la construction des paquets DEB
- vm-srv-build3 — windows 10, pour la construction, vous comprenez bien pourquoi
Nous allons construire — une interface graphique pour 1C rac pour gérer le cluster de serveurs. Sous Linux, les outils par défaut de chaque OS seront utilisés, pour compiler le fichier exe sous Windows à partir d'un script tcl, nous utilisons .
Installation
GNU/Linux
Il existe suffisamment de documentation sur l'installation en ligne. ,Et cela ne pose pas de problèmes particuliers :
Pour le master :
pip3 install buildbot
pip3 install twisted
pip3 install autobahn
pip3 install pysqlite3
pip3 install sqlalchemy sqlalchemy-migrate
pip3 install buildbot-www buildbot-grid-view buildbot-console-view buildbot-waterfall-view
pip3 install python-dateutilPour les « workers », ceci est suffisant :
pip3 install buildbot-workerBien sûr, il serait plus correct de compiler des paquets pour chaque OS, mais cela est en dehors du cadre de cet article. Nous passerons également sous silence la configuration des conteneurs pour le travail, je noterai seulement que j'utilise ProxMox VE. Et il sera également nécessaire d'installer les paquets requis pour chaque OS pour la construction (centos : rpmdevtools, etc. ; debian : build-essential, dh-make, pbuilder, etc.)
Les projets de construction et les services buildbot seront exécutés au nom d'un utilisateur non privilégié, il est donc nécessaire de le créer sur tous les hôtes participants au processus :
adduser buildbotEnsuite, nous allons configurer le démarrage automatique des services, respectivement sur chacun des hôtes (conteneurs) :
Unité systemd pour démarrer le master :
touch /etc/systemd/buildbot-master.service
[Unit]
Description=Service BuildBot master
After=network.target
[Service]
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/master
ExecStart=/usr/local/bin/buildbot start --nodaemon
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.targetet « worker »
touch /etc/systemd/buildbot-worker.service
[Unit]
Description=Service BuildBot worker
After=network.target
[Service]master
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/worker
ExecStart=/usr/local/bin/buildbot-worker start --nodaemon
[Install]
WantedBy=buildbot-master.serviceComme tous les scripts (dans notre cas) se trouvent dans /usr/local/, il faut indiquer le chemin vers eux dans les variables d'environnement :
nano /root/.bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/binAprès cela, il est possible de créer une infrastructure de répertoires pour les « workers » (sur tous les hôtes), pour cela, on se connecte en tant qu'utilisateur buildbot et on exécute les commandes suivantes :
Sur le premier hôte vm-srv-build1 :
su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 CentOS 123456Sur le deuxième hôte vm-srv-build2 :
su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 Debian-10 123456Sur les hôtes workers, le service buildbot-worker peut être démarré.
systemctl start buildbot-workerMS Windows
En tant que « worker » pour la construction sous Windows, une machine virtuelle avec la dernière version de Win10 sera utilisée.
Pour cela, il faut :
- Pour installer tout ce qu'il fallait en Python, il a été nécessaire de télécharger
- 7Zip
Après que tout ce qui précède soit installé, on peut installer le buildbot lui-même :
pip install buildbot-workerCréons le répertoire de travail
md c:workerEt lançons
buildbot-worker start c:workerSi tout fonctionne (voir le journal c:workertwistd.log), alors on peut enregistrer notre « worker » comme un service en ajoutant une entrée dans le registre avec le répertoire de travail (les commandes sont exécutées dans Powershell lancé en tant qu'administrateur) :
buildbot_worker_windows_service.exe --user VM-SRV-BUILD3buildbot --password 123456 --startup auto install
New-ItemProperty -path Registry::HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesBuildBotParameters -Name directories -PropertyType String -Value c:worker
Et on peut démarrer le service
Start-Service buildbotC'est tout pour les « workers », on peut les laisser de côté, toute la gestion se fait depuis le maître.
Configuration du maître
Pour commencer, créons l'infrastructure pour le maître (sur l'hôte principal), pour cela, on se connecte en tant qu'utilisateur buildbot et on exécute les commandes suivantes :
su - buildbot
mkdir /home/buildbot/master
cd ~
buildbot create-master masterPour les paquets prêts, créons le répertoire builds
mkdir /home/buildbot/buildsDans le répertoire /home/buildbot/master/ un fichier master.cfg a été créé. Ce fichier est un code en Python et contient la description de tous les mécanismes de fonctionnement du système, et c'est avec lui que nous allons travailler par la suite.
nano /home/buildbot/master/master.cfgimport os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters
c = BuildmasterConfig = {}
# Description de nos travailleurs.
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}}
# Spécification au maître de quel dépôt surveiller
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
project = 'Rac-GUI',
branches = True,
pollInterval = 60
)
)
# Service de lancement de la construction
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="Rac-GUI-schedulers",
change_filter=util.ChangeFilter(branch='master'),
builderNames=["Rac-GUI-RPM-builder", "Rac-GUI-DEB-builder", "Rac-GUI-WIN-builder"],
properties = {'owner': 'admin'}
)
)
@util.renderer
######################################3
# Construction du paquet RPM
rac_gui_build_RPM = util.BuildFactory()
rac_gui_build_RPM.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
workdir = 'rac-gui',
haltOnFailure = True,
submodules = True,
mode='full',
progress = True)
)Pour automatiser la construction de paquets de différentes versions, afin de ne pas avoir à fouiller dans le code du fichier master.cfg, des lignes avec la version actuelle et le numéro de version ont été ajoutées dans le script principal du programme rac_gui.tcl :
######################################################
# Rac GUI
...
# version: 1.0.3
# release: 1Et sur la base de ces lignes, buildbot numérote les paquets. Pour extraire les données, une commande grep en console est utilisée. Dans buildbot, il n'est pas possible de définir des variables pour les « travailleurs » simplement (en tout cas, je n'ai pas trouvé comment). Les propriétés (property) sont là pour ça. Autrement dit, dans le processus de construction, nous ajoutons des étapes pour déterminer la version et le numéro de version, et par conséquent, nous définissons les propriétés version et release. Les propriétés peuvent être définies de différentes manières, dans ce cas, en appelant une commande console :
# Добавим определение версии из основного файла
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep version ../rac-gui/rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Добавим определение релиза из основного файла
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep release ../rac-gui/rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)Les valeurs obtenues peuvent être insérées en appelant util.Interpolate().
# Запакуем исходники
rac_gui_build_RPM.addStep(
steps.ShellCommand(
command=["tar", "czf", util.Interpolate("/home/buildbot/rpmbuild/SOURCES/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"), "../rac-gui"]
)
)Il convient de noter que, comme l'hôte est également utilisé pour la construction manuelle des paquets, la construction se fera selon les chemins standards.
# Копируем spec
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["cp", "../rac-gui/rac_gui.spec", "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))Pour définir correctement les numéros de version et de release, on utilise un appel à la commande standard sed, c'est-à-dire que la commande remplace les valeurs à l'intérieur du fichier spec par les nécessaires.
# меняем версию
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s/.*Version:.*/Version:t%(prop:version)s/"), "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))
# меняем релиз
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s/.*Release:.*/Release:t%(prop:release)s/"), "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))
# запускаем процесс сборки
rac_gui_build_RPM.addStep(steps.RpmBuild(
specfile="/home/buildbot/rpmbuild/SPECS/rac_gui.spec",
dist='.el5',
topdir='/home/buildbot/rpmbuild',
builddir='/home/buildbot/rpmbuild/build',
rpmdir='/home/buildbot/rpmbuild/RPMS',
sourcedir='/home/buildbot/rpmbuild/SOURCES'
)
)Le paquet construit final et l'archive des sources sont copiés sur le maître. Mais il est également possible de copier directement depuis les fichiers de travail dans votre dépôt ou sur le site.
# Скопируем файл на мастер
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("/home/buildbot/rpmbuild/RPMS/noarch/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")
)
)
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("/home/buildbot/rpmbuild/SOURCES/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")
)
)Lançons sur le maître le processus de copie des paquets construits sur l'hébergement via FTP. Pour cela, il est utilisé en tcl.
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")]
)
)
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")]
)
)Nous en avons fini avec RPM. Passons maintenant à la description de l'algorithme de construction du paquet DEB. Étant donné que les processus de création de paquets pour différents systèmes sont indépendants les uns des autres, de nombreuses étapes seront répétées.
rac_gui_build_DEB = util.BuildFactory()
rac_gui_build_DEB.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)
# Ajoutons la définition de la version à partir du fichier principal
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep version rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Ajoutons la définition de la release à partir du fichier principal
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
# Renommons le fichier exécutable
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["mv", "rac_gui.tcl", "racgui"]))Pour le paquet RPM, une partie des procédures suivantes est effectuée par rpm lors de la construction et est décrite dans la spécification, pour Debian, il faut le faire ici:
# Поменяем пути к библиотекам
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+^set dir(lib)+set dir(lib) /usr/share/rac-gui/lib ;#+g", "racgui"]))
# Поменяем пути к файлам
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+[pwd]+/usr/share/rac-gui+g", "racgui"]))
# заархивируем исходники
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("../rac-gui_%(prop:version)s.orig.tar.gz"), "."]))
# Соберём пакет
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["dpkg-buildpackage"]))
# Скопируем файл на мастер
rac_gui_build_DEB.addStep(
steps.FileUpload(
workersrc=util.Interpolate("../rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")
)
)
rac_gui_build_DEB.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")]
)
)Et voilà, nous avons terminé avec DEB, maintenant passons à Windows !
rac_gui_build_WIN = util.BuildFactory()
rac_gui_build_WIN.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)Étant donné qu'il n'y a pas de grep et de sed par défaut sous Windows (ou peut-être qu'il y en a ?), nous allons utiliser PowerShell.
# Добавим определение версии из основного файла
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
property="version"
)
)
# Добавим определение релиза из основного файла
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
property="release"
)
)
# Создадим запускаемый файл
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:binfreewrap.exe", "rac_gui.tcl"]))
# запакуем то, что получилось
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:Program Files7-zip7z.exe", "a", "-r", util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"), "..build"]))
# скопируем на мастер
rac_gui_build_WIN.addStep(
steps.FileUpload(
workersrc=util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")
)
)
# Скопируем файл на хостинг
rac_gui_build_WIN.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")]
)
)
# Тут определяем какие сборщики у нас есть
c['builders'] = [
util.BuilderConfig(name="Rac-GUI-RPM-builder", workername='CentOS', factory=rac_gui_build_RPM),
util.BuilderConfig(name="Rac-GUI-DEB-builder", workername='Debian-10', factory=rac_gui_build_DEB),
util.BuilderConfig(name="Rac-GUI-WIN-builder", workername='Windows-10', factory=rac_gui_build_WIN),
]Pour notifier sur l'état du processus de construction, nous utiliserons le courrier électronique électronique.
c['services'] = []
template=u'''
<h4>État de la construction : {{ summary }}</h4>
<p> Travailleur utilisé : {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }} : {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Le Buildbot</b></p>
'''
mailNotifier = reporters.MailNotifier(fromaddr="builder@domain.ru",
sendToInterestedUsers=False,
mode=('all'),
extraRecipients=["admin@domain.ru"],
relayhost="mail.domain.ru",
smtpPort=587,
smtpUser="builder@domain.ru",
smtpPassword="******",
messageFormatter=reporters.MessageFormatter(
template=template, template_type='html',
wantProperties=True, wantSteps=True))
c['services'].append(mailNotifier)
# Principales paramètres du maître
c['title'] = "Le processus de construction"
c['titleURL'] = "http://vm-srv-build1:80/"
c['buildbotURL'] = "http://vm-srv-build1/"
c['www'] = dict(port=80,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}))
c['db'] = {
'db_url' : "sqlite:////state.sqlite"
}Enregistrez le fichier et essayons maintenant de redémarrer le service du maître :
systemctl restart buildbot-masterDans le journal, nous vérifierons que tout est en ordre avec la configuration et que tout fonctionne normalement. Tous nos travailleurs devraient maintenant se connecter, ce qui sera joyeusement annoncé dans le journal »»'/home/buildbot/master/twistd.log'»».
2019-07-24 16:50:35+0300 [-] Chargement de buildbot.tac...
2019-07-24 16:50:35+0300 [-] Chargé.
2019-07-24 16:50:35+0300 [-] twistd 19.2.1 (\/usr\/bin\/python3.6 3.6.8) démarrage.
2019-07-24 16:50:35+0300 [-] classe de réacteur : twisted.internet.epollreactor.EPollReactor.
2019-07-24 16:50:35+0300 [-] Démarrage de BuildMaster -- buildbot.version: 2.3.1
2019-07-24 16:50:35+0300 [-] Chargement de la configuration depuis '\/home\/buildbot\/master\/master.cfg'
2019-07-24 16:50:36+0300 [-] \/usr\/local\/lib\/python3.6\/site-packages\/buildbot\/config.py:90: buildbot.config.ConfigWarning: [0.9.0 et ultérieur] `buildbotNetUsageData` n'est pas configuré et par défaut, il est basique.
Ce paramètre aide l'équipe de développement de buildbot à comprendre la base d'installation.
Aucune information personnelle n'est collectée.
Seules des informations sur la version du logiciel d'installation et l'utilisation des plugins sont envoyées.
Vous pouvez vous `désinscrire` en réglant cette variable sur None.
Ou vous `inscrire` pour plus d'informations en réglant ceci sur "full".
2019-07-24 16:50:36+0300 [-] Configuration de la base de données avec l'URL 'sqlite:\/state.sqlite'
2019-07-24 16:50:36+0300 [-] réglage du mode journal de la base de données sur 'wal'
2019-07-24 16:50:36+0300 [-] ajout de 1 nouveau service, suppression de 0
2019-07-24 16:50:36+0300 [-] ajout de 1 nouvelle source de changement, suppression de 0
2019-07-24 16:50:36+0300 [-] gitpoller : répertoire de travail '\/home\/buildbot\/master\/gitpoller-work'
2019-07-24 16:50:36+0300 [-] ajout de 3 nouveaux builders, suppression de 0
2019-07-24 16:50:36+0300 [-] ajout de 1 nouveau planificateur, suppression de 0
2019-07-24 16:50:36+0300 [-] initialisation du plugin www 'waterfall_view'
2019-07-24 16:50:36+0300 [-] initialisation du plugin www 'console_view'
2019-07-24 16:50:36+0300 [-] initialisation du plugin www 'grid_view'
2019-07-24 16:50:36+0300 [-] REMARQUE : le plugin www 'sitenav' est installé mais non configuré
2019-07-24 16:50:36+0300 [-] initialisation du plugin www 'waterfall_view'
2019-07-24 16:50:36+0300 [-] initialisation du plugin www 'console_view'
2019-07-24 16:50:36+0300 [-] initialisation du plugin www 'grid_view'
2019-07-24 16:50:36+0300 [-] REMARQUE : le plugin www 'sitenav' est installé mais non configuré
2019-07-24 16:50:36+0300 [-] BuildbotSite démarrant sur 80
2019-07-24 16:50:36+0300 [-] Démarrage de la fabrique
2019-07-24 16:50:36+0300 [-] ajout de 3 nouveaux travailleurs, suppression de 0
2019-07-24 16:50:36+0300 [-] PBServerFactory démarrant sur 4000
2019-07-24 16:50:36+0300 [-] Démarrage de la fabrique
2019-07-24 16:50:37+0300 [-] BuildMaster est en cours d'exécution
2019-07-24 16:50:37+0300 [-] buildbotNetUsageData : envoi {'installid': 'b6193b126b96689351d2fe95787c5a03fc0879f9', 'versions': {'Python': '3.6.8', 'Buildbot': '2.3.1', 'Twisted': '19.2.1'}, 'platform': {'platform': 'Linux-4.15.18-10- pve-x86_64-with-centos-7.6.1810-Core', 'system': 'Linux', 'machine': 'x86_64', 'processor': 'x86_64', 'python_implementation': 'CPython', 'version': '#1 SMP PVE 4.15.18-32', 'distro': 'centos:7'}, 'plugins': {'buildbot\/worker\/base\/Worker': 3, 'buildbot\/config\/BuilderConfig': 3, 'buildbot\/schedulers\/basic\/SingleBranchScheduler': 1, 'buildbot\/reporters\/mail\/MailNotifier': 1, 'buildbot\/changes\/gitpoller\/GitPoller': 1, 'buildbot\/steps\/worker\/MakeDirectory': 1, 'buildbot\/steps\/source\/git\/Git': 3, 'buildbot\/steps\/shell\/ShellCommand': 9, 'buildbot\/steps\/package\/rpm\/rpmbuild\/RpmBuild': 1}, 'db': 'sqlite', 'mq': 'simple', 'www_plugins': ['waterfall_view', 'console_view', 'grid_view']}
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] travailleur 'CentOS' s'attachant depuis IPv4Address(type='TCP', host='127.0.0.1', port=37332)
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Informations sur le travailleur reçues de 'CentOS'
2019-07-24 16:50:37+0300 [-] bot attaché
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Travailleurs CentOS attachés à Rac-GUI-RPM-builder
2019-07-24 16:50:37+0300 [-] buildbotNetUsageData : buildbot.net a dit : ok
2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] travailleur 'Windows-10' s'attachant depuis IPv4Address(type='TCP', host='192.168.5.145', port=49831)
2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Informations sur le travailleur reçues de 'Windows-10'
2019-07-24 16:50:40+0300 [-] bot attaché
2019-07-24 16:50:40+0300 [Broker,1,192.168.55.15] Travailleurs Windows-10 attachés à Rac-GUI-WIN-builder
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] travailleur 'Debian-10' s'attachant depuis IPv4Address(type='TCP', host='192.168.5.9', port=44430)
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Informations sur le travailleur reçues de 'Debian-10'
2019-07-24 16:50:41+0300 [-] bot attaché
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Travailleurs Debian-10 attachés à Rac-GUI-DEB-builderLa configuration est maintenant terminée. Vous pouvez consulter l'état actuel via l'interface web, où vous pourrez également voir les erreurs de compilation, relancer un processus bloqué si quelque chose ne va pas, etc.
Immédiatement après le lancement de nos travailleurs, vous pouvez le voir dans le menu « Builds » -> « Workers »

Après que le premier processus de compilation a été effectué (c'est-à-dire des changements dans le dépôt Git), l'état des processus apparaîtra sur la première page.

En cliquant sur la ligne appropriée, vous ouvrirez une page avec l'état actuel de ce processus, où vous pouvez voir ce qui se passe, quelles erreurs, etc.

La configuration complète du maître peut être trouvée ici
import os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters
c= BuildmasterConfig ={}
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}}
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
project = 'Rac-GUI',
branches = True,
pollInterval = 600
))
# Service for initiating builds
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="Rac-GUI-schedulers",
change_filter=util.ChangeFilter(branch='master'),
builderNames=["Rac-GUI-RPM-builder", "Rac-GUI-DEB-builder", "Rac-GUI-WIN-builder"],
properties = {'owner': 'admin'}
))
@util.renderer
def get_name_version_release(props):
prog_name = "rac-gui"
prog_version = "1.0.3"
prog_release = "3"
return {
"prog_name": prog_name
#"prog_version": prog_version,
#"prog_release": prog_release
}
rac_gui_build_RPM = util.BuildFactory()
rac_gui_build_RPM.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
workdir = 'rac-gui',
haltOnFailure = True,
submodules = True,
mode='full',
progress = True)
)
# Adding version definition from the main file
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep version ..\/rac-gui\/rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Adding release definition from the main file
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep release ..\/rac-gui\/rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("\/home\/buildbot\/rpmbuild\/SOURCES\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"), "..\/rac-gui"]))
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["cp", "..\/rac-gui\/rac_gui.spec", "\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec"]))
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s\/.*Version:.*\/Version:t%(prop:version)s\/"), "\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec"]))
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s\/.*Release:.*\/Release:t%(prop:release)s\/"), "\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec"]))
rac_gui_build_RPM.addStep(steps.RpmBuild(
specfile="\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec",
dist='.el5',
topdir='\/home\/buildbot\/rpmbuild',
builddir='\/home\/buildbot\/rpmbuild\/build',
rpmdir='\/home\/buildbot\/rpmbuild\/RPMS',
sourcedir='\/home\/buildbot\/rpmbuild\/SOURCES'
))
# Copying file to master
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("\/home\/buildbot\/rpmbuild\/RPMS\/noarch\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")
)
)
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("\/home\/buildbot\/rpmbuild\/SOURCES\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")
)
)
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")]
)
)
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")]
)
)
####################################
## DEB
####################################
rac_gui_build_DEB = util.BuildFactory()
rac_gui_build_DEB.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)
# Adding version definition from the main file
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep version rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Adding release definition from the main file
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
# Rename the executable file
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["mv", "rac_gui.tcl", "racgui"]))
# Change library paths
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+^set dir(lib)+set dir(lib) \/usr\/share\/rac-gui\/lib ;#+g", "racgui"]))
# Change file paths
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+[pwd]+\/usr\/share\/rac-gui+g", "racgui"]))
# Archive the source files
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("..\/rac-gui_%(prop:version)s.orig.tar.gz"), "."]))
# Build the package
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["dpkg-buildpackage"]))
# Copying file to master
rac_gui_build_DEB.addStep(
steps.FileUpload(
workersrc=util.Interpolate("..\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")
)
)
rac_gui_build_DEB.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")]
)
)
############################################
# WIN
############################################
rac_gui_build_WIN = util.BuildFactory()
rac_gui_build_WIN.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)
# Adding version definition from the main file
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
property="version"
)
)
# Adding release definition from the main file
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
property="release"
)
)
# Create the executable file
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:binfreewrap.exe", "rac_gui.tcl"]))
# Zip the output
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:Program Files7-zip7z.exe", "a", "-r", util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"), "..build"]))
# Copying to master
rac_gui_build_WIN.addStep(
steps.FileUpload(
workersrc=util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")
)
)
# Copying file to hosting
rac_gui_build_WIN.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")]
)
)
c['builders'] = [
util.BuilderConfig(name="Rac-GUI-RPM-builder", workername='CentOS', factory=rac_gui_build_RPM),
util.BuilderConfig(name="Rac-GUI-DEB-builder", workername='Debian-10', factory=rac_gui_build_DEB),
util.BuilderConfig(name="Rac-GUI-WIN-builder", workername='Windows-10', factory=rac_gui_build_WIN),
]
c['services'] = []
template=u'''
<h4>État de la construction : {{ summary }}</h4>
<p> Travailleur utilisé : {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }} : {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Le Buildbot</b></p>
'''
mailNotifier = reporters.MailNotifier(fromaddr="112@icvibor.ru",
sendToInterestedUsers=False,
mode=('all'),
extraRecipients=["my@domain.local"],
relayhost="mail.domain.local",
smtpPort=587,
smtpUser="buildbot@domain.local",
smtpPassword="**********",
messageFormatter=reporters.MessageFormatter(
template=template, template_type='html',
wantProperties=True, wantSteps=True))
c['services'].append(mailNotifier)
c['title'] = "Le processus de construction"
c['titleURL'] = "http://vm-srv-build1:80/"
c['buildbotURL'] = "http://vm-srv-build1/"
c['www'] = dict(port=80,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}))
c['db'] = {
'db_url' : "sqlite:////state.sqlite"
}Matériaux
Les matériaux suivants ont été utilisés pour la rédaction de l'article :
- Et la documentation sur le produit
Source : habr.com
