Buildbot în exemple

A trebuit să configurez procesul de construire și livrare pe site a pachetelor de software dintr-un depozit Git. Și văzând, nu de mult aici pe Habr un articol despre buildbot (linkul la sfârșit), am decis să-l încerc și să-l aplic.

Fiindcă buildbot este un sistem distribuit, ar fi logic să facem un host de construire separat pentru fiecare arhitectură și sistem de operare. În cazul nostru, acestea vor fi containere LXC (în cazul Linux) și qemu (în cazul Windows):

  • vm-srv-build1 — centos 7, aici va fi masterul buildbot și unul dintre lucrători
  • vm-srv-build2 — debian 10, pentru construirea pachetelor DEB
  • vm-srv-build3 — windows 10, pentru construirea, știți pentru ce

Vom construi Rac GUI — interfața grafică pentru 1C rac pentru gestionarea clusterului de servere. Pentru Linux se vor folosi instrumentele standard pentru fiecare OS, pentru construcția fișierului exe pentru Windows din scriptul tcl se folosește freewrap.

Instalare

GNU/Linux

Există suficientă documentație online pentru instalare 1,2. De asemenea, nu creează probleme deosebite:
Pentru 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-dateutil

Pentru «workeri», acest lucru este suficient:

pip3 install buildbot-worker

Desigur, ar fi mai corect să construim pachete pentru fiecare OS, dar asta nu face parte din articol. De asemenea, vom omite descrierea configurării containerelor pentru muncă, voi menționa doar că folosesc ProxMox VE. Și va fi necesar să instalăm pachetele necesare pentru fiecare sistem de operare pentru construire (centos: rpmdevtools etc.; debian: build-essential, dh-make, pbuilder etc.)

Construirea proiectelor și serviciile buildbot vor fi lansate în numele unui utilizator neprivilegiat, așa că trebuie să-l creăm pe toate hosturile implicate în proces:


adduser buildbot

Apoi, vom configura lansarea automată a serviciilor, în consecință, pe fiecare dintre hosturi (containere):

Unitatea Systemd pentru lansarea masterului:

touch /etc/systemd/buildbot-master.service 

[Unit]
Description=Serviciul master BuildBot
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.target

și «workerul»

touch /etc/systemd/buildbot-worker.service 

[Unit]
Description=Serviciul worker BuildBot
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.service

Deoarece toate scripturile (în cazul nostru) se află în /usr/local/, este necesar să specificăm calea către ele în variabilele de mediu:

nano /root/.bash_profile

PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/bin

După aceasta, se poate crea infrastructura directorilor pentru „lucrători” (pe toate gazdele), pentru aceasta se înregistrează sub utilizatorul buildbot și se execută următoarele comenzi:

Pe prima gazdă vm-srv-build1:

su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 CentOS 123456

Pe a doua gazdă 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 123456

Pe gazdele-lucrători serviciul buildbot-worker poate fi pornit

systemctl start buildbot-worker

MS Windows

Ca „lucrător” pentru construirea pe Windows, va fi utilizată o mașină virtuală cu cea mai recentă versiune Win10.
Pentru a funcționa, este nevoie de:

După ce tot ce este menționat mai sus se instalează, se poate instala și buildbot în sine:

pip install buildbot-worker

Să creăm directorul de lucru

md c:worker

Și să pornim

buildbot-worker start c:worker

Dacă totul funcționează (vezi log-ul c:workertwistd.log), atunci putem înregistra „lucrătorul” nostru ca serviciu, adăugând în registrul de sistem un element cu directorul de lucru (comenzile se execută în PowerShell deschis ca administrator):

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

Și se poate porni serviciul

Start-Service buildbot

Cu „lucrătorii” aici se termină, apoi nu se mai intervine, toată gestionarea se face din master.

Configurarea masterului

Pentru început, să creăm infrastructura pentru master (pe gazda principală), pentru aceasta se înregistrează sub utilizatorul buildbot și se execută următoarele comenzi:

su - buildbot
mkdir /home/buildbot/master
cd ~
buildbot create-master master

Pentru pachetele gata, să creăm un director builds

mkdir /home/buildbot/builds

În directorul /home/buildbot/master/ a fost creat fișierul master.cfg. Acest fișier reprezintă cod Python și conține descrierea tuturor mecanismelor de funcționare ale sistemului, cu el vom lucra în continuare.

nano /home/buildbot/master/master.cfg

import os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters

c= BuildmasterConfig ={}

# Descrierea lucrătorilor noștri.
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}} 

# Indică maestrului ce depozit să monitorizeze
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
       repourl = 'https://bitbucket.org/svk28/rac-gui.git',
       project = 'Rac-GUI',
       branches = True,
       pollInterval = 60
      )
)

# Serviciul de lansare a construcției
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
# Construirea pachetului 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)
)

Pentru automatizarea construcției pachetelor de versiuni diferite, pentru a nu fi necesar să modificăm codul fișierului master.cfg, au fost adăugate în principalul script al programului rac_gui.tcl linii cu versiunea și release-ul curente:

######################################################
#        Rac GUI
...
# version: 1.0.3
# release: 1

Și pe baza acestor linii, buildbot va număra pachetele. Pentru extragerea datelor, se folosește apelul consolei grep. În buildbot, nu se pot defini variabile pentru „lucrători” (cel puțin, eu nu am găsit cum). Acest lucru se realizează prin proprietăți (property). Adică, în procesul de construcție, adăugăm pașii pentru determinarea versiunii și release-ului și, respectiv, stabilim proprietățile version și release. Proprietățile pot fi setate în diverse moduri, în acest caz fiind apelul unei comenzi 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"
       )
)

Valorile obținute pot fi inserate prin apelul 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"]
       )
)

Aici trebuie menționat că, deoarece gazda este folosită și pentru construcția manuală a pachetelor, construcția va avea loc pe căile standard.

# Копируем spec
rac_gui_build_RPM.addStep(steps.ShellCommand(
       command=["cp", "../rac-gui/rac_gui.spec", "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))

Pentru a stabili numerele corecte de release și versiune, se folosește apelul standard sed, adică comanda înlocuiește valorile din fișierul spec cu cele necesare

# меняем версию
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'
      )
)

Pachetul final construit și arhiva cu sursele sunt copiate pe master. Dar se poate copia și direct de pe lucrător în propriul depozit sau pe 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")
       )
)

Vom lansa pe master procesul de copiere a pachetelor construite pe hosting prin ftp. Pentru aceasta se folosește script în 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")]
        )
)

Am terminat cu RPM. Acum să trecem la descrierea algoritmului de construire a pachetului DEB. Deoarece procesele de construire a pachetelor pentru diferite sisteme sunt independente una de cealaltă, multe dintre pași se vor repeta.


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)
)

# Să adăugăm definiția versiunii din fișierul 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"
       )
)

# Să adăugăm definiția release-ului din fișierul principal
rac_gui_build_DEB.addStep(
       steps.SetPropertyFromCommand(
       command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
       )
)

# Să redenumim fișierul executabil
    rac_gui_build_DEB.addStep(steps.ShellCommand(
       command=["mv", "rac_gui.tcl", "racgui"]))

Pentru pachetul RPM, o parte din procedurile de mai jos sunt realizate de rpm în timpul construirii și sunt descrise în interiorul spec-ului, în timp ce pentru Debian trebuie să le facem aici:

# Поменяем пути к библиотекам
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")]
        )
)

Și cu DEB am terminat, acum trecem la 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)
)

Dat fiind că în Windows nu avem grep și sed (sau poate că avem?), vom folosi 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),
]

Pentru a notifica despre starea procesului de construire, vom folosi poșta electronică.


c['services'] = []

template=u'''
    <h4>Starea construcției: {{ summary }}</h4>
    <p> Lucrător utilizat: {{ workername }}</p>
    {% for step in build['steps'] %}
    <p> {{ step['name'] }}: {{ step['result'] }}</p>
    {% endfor %}
    <p><b> -- Buildbot-ul</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)

# Setările principale ale master-ului
c['title'] = "Procesul de construcție"
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"
}

Salvăm fișierul și putem încerca să pornim serviciul master:

systemctl restart buildbot-master

În jurnal vom verifica că totul este în regulă cu configurația și că funcționează în mod normal. Toți muncitorii noștri ar trebui acum să se conecteze, ceea ce va fi anunțat în jurnal »»’/home/buildbot/master/twistd.log»»’.

 2019-07-24 16:50:35+0300 [-] Încărcare buildbot.tac...
 2019-07-24 16:50:35+0300 [-] Încărcat.
 2019-07-24 16:50:35+0300 [-] twistd 19.2.1 (\/usr\/bin\/python3.6 3.6.8) se pornește.
 2019-07-24 16:50:35+0300 [-] clasa reactor: twisted.internet.epollreactor.EPollReactor.
 2019-07-24 16:50:35+0300 [-] Începerea BuildMaster -- buildbot.version: 2.3.1
 2019-07-24 16:50:35+0300 [-] Încărcare configurație din '\/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 și ulterioare] `buildbotNetUsageData` nu este configurat și revine la setările de bază.
 Acest parametru ajută echipa de dezvoltare a buildbot să înțeleagă baza de instalare.
 Nu sunt colectate informații personale.
 Doar informațiile despre versiunea software-ului instalat și utilizarea plugin-urilor sunt trimise.
 Puteți `opt-out` setând această variabilă la None.
 Sau `opt-in` pentru mai multe informații, setând-o la "full".

 2019-07-24 16:50:36+0300 [-] Configurare bază de date cu URL 'sqlite:\/state.sqlite'
 2019-07-24 16:50:36+0300 [-] setarea modului jurnal al bazei de date la 'wal'
 2019-07-24 16:50:36+0300 [-] adăugare 1 serviciu nou, eliminare 0
 2019-07-24 16:50:36+0300 [-] adăugare 1 sursă de schimbări noi, eliminare 0
 2019-07-24 16:50:36+0300 [-] gitpoller: utilizând directorul de lucru '\/home\/buildbot\/master\/gitpoller-work'
 2019-07-24 16:50:36+0300 [-] adăugare 3 construitori noi, eliminare 0
 2019-07-24 16:50:36+0300 [-] adăugare 1 nou programator, eliminare 0
 2019-07-24 16:50:36+0300 [-] inițializare plugin www 'waterfall_view'
 2019-07-24 16:50:36+0300 [-] inițializare plugin www 'console_view'
 2019-07-24 16:50:36+0300 [-] inițializare plugin www 'grid_view'
 2019-07-24 16:50:36+0300 [-] NOTĂ: plugin ul www 'sitenav' este instalat, dar nu este configurat.
 2019-07-24 16:50:36+0300 [-] inițializare plugin www 'waterfall_view'
 2019-07-24 16:50:36+0300 [-] inițializare plugin www 'console_view'
 2019-07-24 16:50:36+0300 [-] inițializare plugin www 'grid_view'
 2019-07-24 16:50:36+0300 [-] NOTĂ: plugin ul www 'sitenav' este instalat, dar nu este configurat.
 2019-07-24 16:50:36+0300 [-] BuildbotSite pornind pe 80
 2019-07-24 16:50:36+0300 [-] Pornire fabrică <buildbot.www.service.BuildbotSite object at 0x7fe31c2657b8>
 2019-07-24 16:50:36+0300 [-] adăugare 3 lucrători noi, eliminare 0
 2019-07-24 16:50:36+0300 [-] PBServerFactory pornind pe 4000
 2019-07-24 16:50:36+0300 [-] Pornire fabrică <twisted.spread.pb.PBServerFactory object at 0x7fe31c147470>
 2019-07-24 16:50:37+0300 [-] BuildMaster este în execuție
 2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: trimit {'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] lucrător 'CentOS' se atașează de IPv4Address(type='TCP', host='127.0.0.1', port=37332)
 2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Am primit informațiile lucrătorului de la 'CentOS'
 2019-07-24 16:50:37+0300 [-] bot atașat
 2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Lucrătorul CentOS atașat la Rac-GUI-RPM-builder
 2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: buildbot.net a spus: ok
 2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] lucrător 'Windows-10' se atașează de IPv4Address(type='TCP', host='192.168.5.145', port=49831)
 2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Am primit informațiile lucrătorului de la 'Windows-10'
 2019-07-24 16:50:40+0300 [-] bot atașat
 2019-07-24 16:50:40+0300 [Broker,1,192.168.55.15] Lucrătorul Windows-10 atașat la Rac-GUI-WIN-builder
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] lucrător 'Debian-10' se atașează de IPv4Address(type='TCP', host='192.168.5.9', port=44430)
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Am primit informațiile lucrătorului de la 'Debian-10'
 2019-07-24 16:50:41+0300 [-] bot atașat
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Lucrătorul Debian-10 atașat la Rac-GUI-DEB-builder

Acest proces de configurare s-a încheiat. Puteți verifica starea curentă prin intermediul interfeței web, unde puteți observa, de asemenea, erorile de construcție, să reporniti procesele blocate dacă ceva nu a mers bine etc.

Imediat după ce muncitorii noștri sunt activi, puteți verifica prin meniul „Builds” -> „Workers”

Buildbot în exemple

După ce va fi finalizat primul proces de construcție (adică modificările din repository-ul Git), pe prima pagină va apărea starea proceselor.

Buildbot în exemple

Dacă faceți clic pe linia dorită, se va deschide o pagină cu starea curentă a acestui proces, unde se poate observa ce se întâmplă, ce erori sunt etc.

Buildbot în exemple

Întreaga configurație a maestrului poate fi găsită aici

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
    ))

# Serviciul de lansare a compilării
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)
    )

# Să adăugăm definirea versiunii din fișierul principal
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"
    )
)

# Să adăugăm definirea release-ului din fișierul principal
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'
    ))

# Să copiem fișierul pe server
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)
    )

# Să adăugăm definirea versiunii din fișierul 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"
    )
)

# Să adăugăm definirea release-ului din fișierul principal
rac_gui_build_DEB.addStep(
    steps.SetPropertyFromCommand(
    command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
    )
)

# Să redenumim fișierul executabil
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["mv", "rac_gui.tcl", "racgui"]))

# Să schimbăm căile către biblioteci
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["sed", "-i", "s+^set dir(lib)+set dir(lib) \/usr\/share\/rac-gui\/lib ;#+g", "racgui"]))

# Să schimbăm căile către fișiere
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["sed", "-i", "s+[pwd]+\/usr\/share\/rac-gui+g", "racgui"]))

# Să arhivăm sursele
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["tar", "czf", util.Interpolate("..\/rac-gui_%(prop:version)s.orig.tar.gz"), "."]))

# Să construim pachetul
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["dpkg-buildpackage"]))

# Să copiem fișierul pe server
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)
    )

# Să adăugăm definirea versiunii din fișierul principal
rac_gui_build_WIN.addStep(
    steps.SetPropertyFromCommand(
    command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
    property="version"
    )
)

# Să adăugăm definirea release-ului din fișierul principal
rac_gui_build_WIN.addStep(
    steps.SetPropertyFromCommand(
    command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
    property="release"
    )
)

# Să creăm fișierul executabil
rac_gui_build_WIN.addStep(steps.ShellCommand(
    command=["c:binfreewrap.exe", "rac_gui.tcl"]))

# Să comprimăm ce am obținut
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"]))

# Să copiem pe server
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")
    )
)

# Să copiem fișierul pe 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>Starea construcției: {{ summary }}</h4>
<p> Lucrător utilizat: {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }}: {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Buildbot-ul</b></p>
'''

mailNotifier = reporters.MailNotifier(fromaddr="112@icvibor.ro",
          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'] = "Procesul de construcție"
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"
}

Materiale

Pentru pregătirea articolului au fost utilizate următoarele materiale:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster