Ich musste den Prozess der Erstellung und Lieferung von Softwarepaketen aus einem Git-Repository auf die Website einrichten. Und nachdem ich vor nicht allzu langer Zeit hier auf Habr einen Artikel über Buildbot gesehen hatte (Link am Ende), beschloss ich, es auszuprobieren und anzuwenden.
Da Buildbot ein verteiltes System ist, wird es sinnvoll sein, für jede Architektur und jedes Betriebssystem einen eigenen Build-Host einzurichten. In unserem Fall werden dies LXC-Container (im Fall von Linux) und QEMU (im Fall von Windows) sein:
- vm-srv-build1 - CentOS 7, hier wird der Buildbot-Master (master) und einer der Worker (worker) sein.
- vm-srv-build2 - Debian 10, für die Erstellung von DEB-Paketen.
- vm-srv-build3 - Windows 10, für die Erstellung, Sie verstehen schon, wofür.
Wir werden erstellen — die grafische Benutzeroberfläche für 1C rac zur Verwaltung eines Serverclusters. Unter Linux werden die integrierten Mittel für jedes Betriebssystem verwendet, um die EXE-Datei unter Windows aus einem TCL-Skript zu erstellen, verwenden wir .
Installation
GNU/Linux
Es gibt genügend Informationen zur Installation und Dokumentation im Netz. ,Und sie verursacht auch keine besonderen Probleme:
Für den 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-dateutilFür die «Worker» reicht das:
pip3 install buildbot-workerNatürlich wäre es besser, die Pakete für jedes Betriebssystem zu erstellen, aber das fällt nicht in den Rahmen dieses Artikels. Lassen wir auch die Beschreibung der Containerkonfiguration für die Arbeit weg, ich möchte nur erwähnen, dass ich ProxMox VE verwende. Und es ist auch notwendig, die notwendigen Pakete für den Build unter jedem Betriebssystem zu installieren (CentOS: rpmdevtools usw.; Debian: build-essential, dh-make, pbuilder usw.)
Die Projekte und Buildbot-Dienste werden unter dem Namen eines nicht privilegierten Benutzers gestartet, daher muss dieser auf allen Hosts, die am Prozess teilnehmen, erstellt werden:
adduser buildbotAls nächstes richten wir den automatischen Start der Dienste entsprechend auf jedem der Hosts (Container) ein:
Systemd-Einheit zum Starten des Masters:
touch /etc/systemd/buildbot-master.service
[Unit]
Description=BuildBot-Masterdienst
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.targetund «Worker»
touch /etc/systemd/buildbot-worker.service
[Unit]
Description=BuildBot-Workerdienst
After=network.target
[Service]
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/worker
ExecStart=/usr/local/bin/buildbot-worker start --nodaemon
[Install]
WantedBy=buildbot-master.serviceDa alle Skripte (in unserem Fall) im /usr/local/ liegen, sollte der Pfad zu ihnen in den Umgebungsvariablen festgelegt werden:
nano /root/.bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/binNach diesem Schritt kann eine Verzeichnisstruktur für die „Arbeiter“ (auf allen Hosts) erstellt werden. Dazu melden wir uns als Benutzer buildbot an und führen die folgenden Befehle aus:
Auf dem ersten Host vm-srv-build1:
su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 CentOS 123456Auf dem zweiten Host 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 123456Auf den Worker-Hosts kann der Dienst buildbot-worker gestartet werden.
systemctl start buildbot-workerMS Windows
Als „Arbeiter“ für den Build unter Windows wird eine virtuelle Maschine mit der neuesten Version von Win10 verwendet.
Für die Arbeit wird Folgendes benötigt:
- Um verschiedene Dinge in Python zu installieren, musste folgendes heruntergeladen werden:
- 7Zip
Nachdem alles oben Genannte installiert ist, kann auch buildbot selbst installiert werden:
pip install buildbot-workerErstellen wir ein Arbeitsverzeichnis.
md c:workerUnd starten wir es.
buildbot-worker start c:workerWenn alles funktioniert (siehe Log c:workertwistd.log), kann unser „Arbeiter“ als Dienst registriert werden, indem ein Eintrag mit dem Arbeitsverzeichnis in die Registrierung hinzugefügt wird (Befehle werden in PowerShell mit Administratorrechten ausgeführt):
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
Und der Dienst kann gestartet werden.
Start-Service buildbotMit den „Arbeitern“ ist hier alles, sie können weiter ignoriert werden, die gesamte Verwaltung erfolgt vom Master aus.
Konfiguration des Masters
Zunächst erstellen wir eine Infrastruktur für den Master (auf dem Haupt-Host). Dazu melden wir uns als Benutzer buildbot an und führen die folgenden Befehle aus:
su - buildbot
mkdir /home/buildbot/master
cd ~
buildbot create-master masterFür die fertigen Pakete erstellen wir ein Verzeichnis builds.
mkdir /home/buildbot/buildsIm Verzeichnis /home/buildbot/master/ wurde die Datei master.cfg erstellt. Diese Datei enthält Python-Code und beschreibt alle Mechanismen der Systemarbeit, mit denen wir in Zukunft arbeiten werden.
nano /home/buildbot/master/master.cfgimport os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters
c= BuildmasterConfig ={}
# Beschreibung unserer Arbeiter.
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}}
# Angabe an den Master, welches Repository beobachtet werden soll
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
project = 'Rac-GUI',
branches = True,
pollInterval = 60
)
)
# Dienst zum Starten des 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
######################################3
# Erstellen des RPM-Pakets
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)
)Um den Aufbau von Paketen verschiedener Versionen zu automatisieren, ohne den Code der Datei master.cfg durchsehen zu müssen, wurden in dem Hauptskript der Programme rac_gui.tcl Zeilen mit der aktuellen Version und dem Release hinzugefügt:
######################################################
# Rac GUI
...
# version: 1.0.3
# release: 1Und basierend auf diesen Zeilen wird der buildbot die Pakete nummerieren. Um die Daten zu extrahieren, wird der Konsolenbefehl grep verwendet. Im buildbot kann man Variablen für „Arbeiter“ nicht einfach so definieren (zumindest habe ich nicht herausgefunden wie). Dafür dienen Eigenschaften (property). Das heißt, wir fügen dem Buildprozess Schritte zur Bestimmung von Version und Release hinzu und setzen entsprechend die Eigenschaften version und release. Eigenschaften können auf verschiedene Arten festgelegt werden, in diesem Fall durch den Aufruf eines Konsolenbefehls:
# Добавим определение версии из основного файла
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"
)
)Die erhaltenen Werte können durch den Aufruf von util.Interpolate() eingesetzt werden.
# Запакуем исходники
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"]
)
)Hier sollte erwähnt werden, dass, da der Host auch für manuelles Erstellen von Paketen verwendet wird, der Aufbau nach den standardmäßigen Pfaden erfolgen wird.
# Копируем spec
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["cp", "../rac-gui/rac_gui.spec", "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))Zur korrekten Einstellung der Release- und Versionsnummern wird der standardmäßige sed-Befehl verwendet, d.h. das Kommando ersetzt die Werte innerhalb der spec-Datei durch die notwendigen.
# меняем версию
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'
)
)Das fertig erstellte Paket und das Archiv mit den Quellcodes werden auf den Master kopiert. Aber man kann auch direkt von den Arbeitsdateien in das eigene Repository oder auf die Website kopieren.
# Скопируем файл на мастер
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")
)
)Wir werden auf dem Master den Prozess starten, um die erstellten Pakete über FTP auf den Hosting-Server zu kopieren. Dazu wird verwendet: auf 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")]
)
)Wir sind mit RPM fertig. Jetzt beginnen wir mit der Beschreibung des DEB-Paketaufbaualgorithmus. Da die Paketbuild-Prozesse für verschiedene Systeme unabhängig voneinander sind, werden viele Schritte wiederholt.
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)
)
# Fügen wir die Versionsdefinition aus der Hauptdatei hinzu
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"
)
)
# Fügen wir die Release-Definition aus der Hauptdatei hinzu
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
# Benennen wir die ausführbare Datei um
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["mv", "rac_gui.tcl", "racgui"]))Für das RPM-Paket werden einige der folgenden Verfahren von rpm während des Builds automatisch durchgeführt und im Spec beschrieben. Für Debian müssen wir dies hier tun:
# Поменяем пути к библиотекам
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")]
)
)Und mit DEB sind wir fertig, jetzt 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)
)Da es unter Windows normalerweise kein grep und sed gibt (oder doch?), werden wir PowerShell verwenden.
# Добавим определение версии из основного файла
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),
]Für die Benachrichtigung über den Status des Build-Prozesses werden wir E-Mail verwenden.
c['services'] = []
template=u'''
<h4>Bauzustand: {{ summary }}</h4>
<p> Verwendeter Arbeiter: {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }}: {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Der 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)
# Hauptkonfiguration des Masters
c['title'] = "Der Prozess des Bauens"
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"
}Wir speichern die Datei und können versuchen, den Master-Dienst zu starten:
systemctl restart buildbot-masterIm Log werden wir überprüfen, dass mit der Konfiguration alles in Ordnung ist und alles normal funktioniert. Alle unsere Worker sollten sich jetzt verbinden, was im Log »»’/home/buildbot/master/twistd.log»»’ freudig mitgeteilt wird:
2019-07-24 16:50:35+0300 [-] Lade buildbot.tac...
2019-07-24 16:50:35+0300 [-] Geladen.
2019-07-24 16:50:35+0300 [-] twistd 19.2.1 (/usr/bin/python3.6 3.6.8) startet.
2019-07-24 16:50:35+0300 [-] Reaktor-Klasse: twisted.internet.epollreactor.EPollReactor.
2019-07-24 16:50:35+0300 [-] Starte BuildMaster -- buildbot.version: 2.3.1
2019-07-24 16:50:35+0300 [-] Lade Konfiguration von '/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 und später] `buildbotNetUsageData` ist nicht konfiguriert und fällt auf die Standardwerte zurück.
Dieses Parameter hilft dem Buildbot-Entwicklungsteam, die Installationsbasis zu verstehen.
Es werden keine persönlichen Informationen gesammelt.
Nur Versionsinformationen der Installationssoftware und die Nutzung von Plugins werden gesendet.
Sie können sich abmelden, indem Sie diese Variable auf None setzen.
Oder sich anmelden, um mehr Informationen zu erhalten, indem Sie es auf "full" setzen.
2019-07-24 16:50:36+0300 [-] Richten Sie die Datenbank mit der URL 'sqlite:/state.sqlite' ein
2019-07-24 16:50:36+0300 [-] Setze den Datenbank-Journalmodus auf 'wal'
2019-07-24 16:50:36+0300 [-] Füge 1 neuen Dienst hinzu, entferne 0
2019-07-24 16:50:36+0300 [-] Füge 1 neue Änderungsquelle hinzu, entferne 0
2019-07-24 16:50:36+0300 [-] gitpoller: benutze Arbeitsverzeichnis '/home/buildbot/master/gitpoller-work'
2019-07-24 16:50:36+0300 [-] Füge 3 neue Builder hinzu, entferne 0
2019-07-24 16:50:36+0300 [-] Füge 1 neuen Scheduler hinzu, entferne 0
2019-07-24 16:50:36+0300 [-] Initialisiere www-Plugin 'waterfall_view'
2019-07-24 16:50:36+0300 [-] Initialisiere www-Plugin 'console_view'
2019-07-24 16:50:36+0300 [-] Initialisiere www-Plugin 'grid_view'
2019-07-24 16:50:36+0300 [-] HINWEIS: www-Plugin 'sitenav' ist installiert, aber nicht konfiguriert
2019-07-24 16:50:36+0300 [-] Initialisiere www-Plugin 'waterfall_view'
2019-07-24 16:50:36+0300 [-] Initialisiere www-Plugin 'console_view'
2019-07-24 16:50:36+0300 [-] Initialisiere www-Plugin 'grid_view'
2019-07-24 16:50:36+0300 [-] HINWEIS: www-Plugin 'sitenav' ist installiert, aber nicht konfiguriert
2019-07-24 16:50:36+0300 [-] BuildbotSite startet auf 80
2019-07-24 16:50:36+0300 [-] Starte Fabrik
2019-07-24 16:50:36+0300 [-] Füge 3 neue Worker hinzu, entferne 0
2019-07-24 16:50:36+0300 [-] PBServerFactory startet auf 4000
2019-07-24 16:50:36+0300 [-] Starte Fabrik
2019-07-24 16:50:37+0300 [-] BuildMaster läuft
2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: sending {'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-mit-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] Worker 'CentOS' verbindet sich von IPv4Address(type='TCP', host='127.0.0.1', port=37332)
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Empfangene Workerinfo von 'CentOS'
2019-07-24 16:50:37+0300 [-] Bot verbunden
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Worker CentOS verbunden mit Rac-GUI-RPM-builder
2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: buildbot.net sagte: ok
2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Worker 'Windows-10' verbindet sich von IPv4Address(type='TCP', host='192.168.5.145', port=49831)
2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Empfangene Workerinfo von 'Windows-10'
2019-07-24 16:50:40+0300 [-] Bot verbunden
2019-07-24 16:50:40+0300 [Broker,1,192.168.55.15] Worker Windows-10 verbunden mit Rac-GUI-WIN-builder
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Worker 'Debian-10' verbindet sich von IPv4Address(type='TCP', host='192.168.5.9', port=44430)
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Empfangene Workerinfo von 'Debian-10'
2019-07-24 16:50:41+0300 [-] Bot verbunden
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Worker Debian-10 verbunden mit Rac-GUI-DEB-builderDer Prozess der Einstellungen ist nun abgeschlossen. Der aktuelle Status kann über die Web-Oberfläche eingesehen werden, wo auch Fehler beim Build angezeigt werden, und ein festgefahrener Prozess neu gestartet werden kann, falls etwas schiefgeht, usw.
Sobald unsere Arbeiter gestartet werden, kann man sie über das Menü „Builds“ -> „Workers“ einsehen.

Nachdem der erste Build-Prozess (d.h. Änderungen im Git-Repository) durchgeführt wurde, wird auf der ersten Seite der Status der Prozesse angezeigt.

Wenn man mit der Maus auf die entsprechende Zeile klickt, öffnet sich eine Seite mit dem aktuellen Status dieses Prozesses, wo sichtbar ist, was passiert, welche Fehler aufgetreten sind, usw.

Die komplette Konfiguration des Masters kann hier heruntergeladen werden.
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
))
# Builddienst starten
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)
)
# Versionsbestimmung aus der Hauptdatei hinzufügen
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"
)
)
# Release-Bestimmung aus der Hauptdatei hinzufügen
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'
))
# Datei auf den Master kopieren
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)
)
# Versionsbestimmung aus der Hauptdatei hinzufügen
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"
)
)
# Release-Bestimmung aus der Hauptdatei hinzufügen
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
# Ausführbare Datei umbenennen
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["mv", "rac_gui.tcl", "racgui"]))
# Bibliothekspfade ändern
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+^set dir(lib)+set dir(lib) /usr/share/rac-gui/lib ;#+g", "racgui"]))
# Datei-Pfade ändern
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+[pwd]/usr/share/rac-gui+g", "racgui"]))
# Quellcode archivieren
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("../rac-gui_%(prop:version)s.orig.tar.gz"), "."]))
# Paket erstellen
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["dpkg-buildpackage"]))
# Datei auf den Master kopieren
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)
)
# Versionsbestimmung aus der Hauptdatei hinzufügen
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
property="version"
)
)
# Release-Bestimmung aus der Hauptdatei hinzufügen
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
property="release"
)
)
# Ausführbare Datei erstellen
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:binfreewrap.exe", "rac_gui.tcl"]))
# packen, was erhalten wurde
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"]))
# auf den Master kopieren
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")
)
)
# Datei auf das Hosting kopieren
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>Bauzustand: {{ summary }}</h4>
<p> Verwendeter Arbeiter: {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }}: {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Der 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'] = "Der Prozess des Bauens"
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"
}Materialien
Für die Erstellung des Artikels wurden folgende Materialien verwendet:
- Und die Dokumentation zum Produkt.
Quelle: habr.com
