ïŒç»åã«ãã
ÐÑОвеÑïŒ
ç§ã®åå㯠ãšãã²ããŒã»ãã§ã«ãã³, ç§ã¯é±å±±äŒç€Ÿã®éçºããŒã ã®ããã°ã©ããŒã§ãã ããªã¡ã¿ã«.
倧èŠæš¡ãªãããžã§ã¯ããéå§ãããšããããããžã§ã¯ããç¶æããã«ã¯ã©ã®ãœãããŠã§ã¢ã䜿çšããã®ãæé©ã?ããšèãå§ããŸãã IT ãããžã§ã¯ãã¯ã次ã®ããŒãžã§ã³ããªãªãŒã¹ãããŸã§ã«ããã€ãã®æ®µéãçµãŸãã ãããã®æ®µéã®é£éãèªååããããšè¯ãã§ãããã IT ãããžã§ã¯ãèªäœã®æ°ããããŒãžã§ã³ããªãªãŒã¹ããèªååãããããã»ã¹ã¯ã ç¶ç¶çã€ã³ãã°ã¬ãŒã·ã§ã³. ãã«ãããã ãã®ããã»ã¹ãå®è£ ããéã«ãç§ãã¡ã«ãšã£ãŠåªããã¢ã·ã¹ã¿ã³ãã§ããããšãããããŸããã
ãã®èšäºã§ã¯ãå¯èœæ§ã®æŠèŠãæäŸããããšã«ããŸãã ãã«ããããã ãã®ãœãããŠã§ã¢ã«ã¯äœãã§ããã®ã§ãããã? 圌ã«ã©ã®ããã«ã¢ãããŒããã圌ãšéåžžã®å¹æçãªä»äºé¢ä¿ãç¯ãã«ã¯ã©ãããã°ããã§ãããã? èªåã®ãã·ã³äžã§ãããžã§ã¯ããæ§ç¯ããŠãã¹ãããããã®å®çšçãªãµãŒãã¹ãäœæããããšã§ãç§ãã¡ã®çµéšãèªåã§é©çšããããšãã§ããŸãã
ããŒãžå
容
ããŒãžå 容
1.ãªãBuildBotãªã®ã?
以åãhabr-e ã§å®è£
ã«é¢ããèšäºãèŠã€ããŸããã ç¶ç¶çã€ã³ãã°ã¬ãŒã·ã§ã³ ã䜿çšã㊠ãã«ããããã äŸãã°
åæ¢ïŒ å®éã«ãããžã§ã¯ãã§äœ¿çšãã人ã¯ããŸãã? ããã§ã
ã§ã¯ã人ã ã䜿çšããŠããããžãã¯ã¯äœã§ãã ãã«ãããã? çµå±ã®ãšãããä»ã«ãããŒã«ããããŸãã ã¯ã«ãŒãºã³ã³ãããŒã« О ãžã§ã³ãã³ãºã ç§ã¯ããçããŸãã ã»ãšãã©ã®ã¿ã¹ã¯ã§ã¯ ãžã§ã³ãã³ãº ãããŠçå®ã ãã§ååã ããã ãã®é çªã§ã ãã«ãããã - ããé©å¿æ§ãé«ããåé¡ã¯ããã§ãåãããã«ç°¡åã«è§£æ±ºãããŸãã ãžã§ã³ãã³ãºã éžæã¯ããªã次第ã§ãã ããããéçºå¯Ÿè±¡ãããžã§ã¯ãçšã®ããŒã«ãæ¢ããŠããã®ã§ããããç°¡åãªæé ãã察話æ§ãšç¬èªã®ã€ã³ã¿ãŒãã§ã€ã¹ãåãããã«ã ã·ã¹ãã ãååŸã§ããããŒã«ãéžæããŠã¿ãŠã¯ãããã§ããããã
ã¿ãŒã²ãã ãããžã§ã¯ãã Python ã§èšè¿°ãããŠããå Žåãããããžã§ã¯ãã§äœ¿çšãããèšèªã«é¢ããŠæ確ãªã€ã³ã¿ãŒãã§ã€ã¹ãåããçµ±åã·ã¹ãã ãéžæããŠã¯ã©ãã§ãããã?ããšããçåãçããŸãã ãããŠä»åºŠã¯ã¡ãªããã玹ä»ããŸã ãã«ãããã.
ãšããããšã§ãç§ãã¡ã®ãåšæ¥œåéå¥å£ãã ç§èªèº«ãXNUMXã€ã®ç¹åŸŽãç¹å®ããŸãã ãã«ãããã:
- GPLã©ã€ã»ã³ã¹ã«åºã¥ããªãŒãã³ãœãŒã¹ãã¬ãŒã ã¯ãŒã¯ã§ã
- ããã¯ãæ§æããŒã«ãšããŠã® Python ã®äœ¿çšãšå¿ èŠãªã¢ã¯ã·ã§ã³ã®èª¬æã§ãã
- ããã¯ãçµã¿ç«ãŠãè¡ããããã·ã³ããã®å¿çãåãåãæ©äŒã§ãã
- æåŸã«ããããã¯ãã¹ãã®æå°èŠä»¶ã§ãã ãããã€ã«ã¯ Python ãšTwisted ãå¿ èŠã§ãããä»®æ³ãã·ã³ã Java ãã·ã³ã¯å¿ èŠãããŸããã
2. BuildMasteräž»å°ã®ã³ã³ã»ãã
ã¿ã¹ã¯åæ£ã¢ãŒããã¯ãã£ã®äžå¿ãšãªãã®ã¯ã ãã«ããã¹ã¿ãŒã ããã¯æ¬¡ã®ãããªãµãŒãã¹ã§ãã
- 远跡ããŸã ãããžã§ã¯ãã®ãœãŒã¹ããªãŒã®å€æŽ
- éã ãããžã§ã¯ãããã«ãããŠãã¹ãããããã« Worker ãµãŒãã¹ã«ãã£ãŠå®è¡ãããå¿ èŠãããã³ãã³ã
- éç¥ãã ãŠãŒã¶ãŒããšã£ãã¢ã¯ã·ã§ã³ã®çµæã«ã€ããŠ
ãã«ããã¹ã¿ãŒ ãã¡ã€ã«çµç±ã§èšå® ãã¹ã¿ãŒ.cfgã ãã®ãã¡ã€ã«ã¯ã«ãŒãã«ãããŸã ãã«ããã¹ã¿ãŒã ãã®ã«ãŒããã©ã®ããã«äœæãããããåŸã§èª¬æããŸãã ãã¡ã€ã«èªäœ ãã¹ã¿ãŒ.cfg åŒã³åºãã䜿çšãã Python ã¹ã¯ãªãããå«ãŸããŠããŸã ãã«ãããã.
次ã«éèŠãªãªããžã§ã¯ã ãã«ãããã ããã¯ãååãæã£ãŠããŸã ã¯ãŒã«ãŒã ãã®ãµãŒãã¹ã¯ãå¥ã® OS ãæèŒããå¥ã®ãã¹ãäžã§èµ·åã§ããŸãããããã¯ã ãã«ããã¹ã¿ãŒã ç¬èªã®ããã±ãŒãžãšå€æ°ãåããç¹å¥ã«æºåãããä»®æ³ç°å¢ã«ååšããããšãã§ããŸãã ãããã®ä»®æ³ç°å¢ã¯ã次ã®ãã㪠Python ãŠãŒãã£ãªãã£ã䜿çšããŠæºåã§ããŸãã ä»®æ³ç°å¢ãvenv.
ãã«ããã¹ã¿ãŒ ã³ãã³ããå šå¡ã«ãããŒããã£ã¹ãããŸã ã¯ãŒã«ãŒ-yããããŠåœŒã¯é çªã«ããããæºãããŸãã ã€ãŸãããããžã§ã¯ãã®æ§ç¯ãšãã¹ãã®ããã»ã¹ãç¶è¡ã§ããããšãããããŸãã ã¯ãŒã«ãŒ-e 㯠Windows ãå®è¡ããå¥ã® Worker ã§ã¯ Linux ãå®è¡ããŸãã
ãã§ãã¯ã¢ãŠã ãããžã§ã¯ãã®ãœãŒã¹ã³ãŒãã¯ããããã«çºçããŸã ã¯ãŒã«ãŒããã
3. ã€ã³ã¹ããŒã«
ãããè¡ããã ãã¹ããšã㊠Ubuntu 18.04 ã䜿çšããŸãã ãã®äžã«XNUMXã€çœ®ããŸã ãã«ããã¹ã¿ãŒ-aãšXNUMX ã¯ãŒã«ãŒ-a. ãã ããæåã« python3.7 ãã€ã³ã¹ããŒã«ããå¿ èŠããããŸãã
sudo apt-get update
sudo apt-get install python3.7
3.7.2 ã®ä»£ããã« Python3.7.1 ãå¿ èŠãªå Žåã¯ã次ã®æé ãå®è¡ã§ããŸãã
sudo apt-get update
sudo apt-get software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get install python3.7
sudo ln -fs /usr/bin/python3.7 /usr/bin/python3
pip3 install --upgrade pip
次ã®ã¹ãããã¯ã€ã³ã¹ããŒã«ã§ã ãã€ãŒãããŸãã О ãã«ãããããè¿œå æ©èœã䜿çšã§ããããã«ããããã±ãŒãžãå«ãŸããŸãã ãã«ãããã-ãããŠã
/*ÐÑе ÑÑП пПЎ sudo бÑÐŽÐµÑ ÑÑÑаМПвлеММП ÐŽÐ»Ñ Ð²ÑеÑ
пПлÑзПваÑелей в ЎОÑекÑПÑÐžÑ /usr/local/lib/python3.7/dist-packages*/
#Ðа Ñ
ПÑÑе кПÑПÑÑй пÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑ ÐŒÐŸÐœÐžÑПÑОМг Worker-Пв
sudo pip install twisted #ÐОблОПÑека twisted
sudo pip install buildbot #BuildMaster
#ÐПпПлМОÑелÑÐœÑй ÑÑМкÑОПМал
pip install pysqlite3 #УÑÑаМавлОваеЌ Ð±Ð°Ð·Ñ sqllite в ÑÑебМÑÑ
ÑелÑÑ
pip install jinja2 #framework МапПЎПбОе django, ÐŽÐ»Ñ web О ÐŽÐ»Ñ Ð¿ÐŸÑÑПвÑÑ
ÑаÑÑÑллПк
pip install autobahn #Web cПкеÑÑ ÐŽÐ»Ñ ÑвÑзО BuildMaster->Worker
pip install sqlalchemy sqlalchemy-migrate #ÐÐ»Ñ ÐŸÑПбÑÐ°Ð¶ÐµÐœÐžÑ ÑÑ
ÐµÐŒÑ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
#ÐÐ»Ñ Web ПÑПбÑÐ°Ð¶ÐµÐœÐžÑ BuildBot-a
pip install buildbot-www buildbot-grid-view buildbot-console-view buildbot-waterfall-view
pip install python-dateutil #ÐÑПбÑажеМОе ÐŽÐ°Ñ Ð² web
#Ðа ÑÑПÑПМе Ñ
ПÑÑа кПÑПÑÑй МепПÑÑеЎÑÑвеММП ПÑÑÑеÑÑвлÑÐµÑ ÑбПÑÐºÑ Ðž ÑеÑÑОÑПваМОе
pip install buildbot-worker #Worker
#ÐПпПлМОÑелÑÐœÑй ÑÑМкÑОПМал
sudo pip install virtualenv #ÐОÑÑÑалÑÐœÐ°Ñ ÑÑеЎа
4. æåã®ã¹ããã
äœæããæé ãã«ããã¹ã¿ãŒã ããã¯ç§ãã¡ã®ãã©ã«ããŒã«ãããŸã /ããŒã /ãã/ãã¹ã¿ãŒ.
mkdir master
buildbot create-master master # СПбÑÑвеММП ÑЎеÑÑ Ðž ÑПзЎаеЌ
mkdir worker
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker localhost:4000 yourWorkerName password
èµ°ããšã ã¯ãŒã«ãŒãããã©ã«ãã§ã¯ã次ã®å Žæã«äœæãããŸãã /ããŒã /ãã/ã¯ãŒã«ãŒ ã§æå®ãããããžã§ã¯ãåã®ãã©ã«ã㌠ãã¹ã¿ãŒ.cfgã ãããŠããããžã§ã¯ãã®ååã®ãã©ã«ããŒã«ãã£ã¬ã¯ããªãäœæãããŸã ãã«ããããããããã£ãŠãããŸã ãã§ãã¯ã¢ãŠãã ã®äœæ¥ãã£ã¬ã¯ã㪠ã¯ãŒã«ãŒ-ãããŠããã¯ãã£ã¬ã¯ããªã«ãªããŸã /home/habr/yourProject/build.
ãé»éã®éµã
ããŠãåã®æ®µèœã§æžããã¹ã¯ãªããã¯æ¬¡ã®ãšããã§ãã Master ããèŠæ±ããŸã ã¯ãŒã«ãŒ-ãã®ãã£ã¬ã¯ããªã§ãªã¢ãŒãã§å®è¡ãããå Žåãã¹ã¯ãªããã«ã¯å®è¡æš©éããªããããå®è¡ãããŸããã ç¶æ³ãä¿®æ£ããã«ã¯ããŒãå¿
èŠã§ã
ãã«ããã¹ã¿ãŒ О ã¯ãŒã«ãŒ çžäºã«æ¥ç¶ã確ç«ããŸãã åããŠããŸãããšããããã ã¯ãŒã«ãŒ ããã®å¿çããã°ããåŸ ã¡ãŸã ãã«ããã¹ã¿ãŒ-A. å¿çããªãå Žåã¯ãæ¥ç¶ãåéãããŸãã éµ --ããŒãã¢ã©ã€ã=60 ãã®åŸã®æéã瀺ãã ãã§ååã§ã æ¥ç¶ãã åèµ·åããŸãã
5. èšå®ã ã¹ããããã€ã¹ãããã®ã¬ã·ã
èšå® ãã«ããã¹ã¿ãŒ ã³ãã³ããå®è¡ãããã·ã³åŽã§å®è¡ãããŸã äœæãã¹ã¿ãŒã ç§ãã¡ã®å Žåãããã¯ãã£ã¬ã¯ããªã§ã /ããŒã /ãã/ãã¹ã¿ãŒã èšå®ãã¡ã€ã« ãã¹ã¿ãŒ.cfg ãŸã ååšããŸããããã³ãã³ãèªäœããã§ã«ãã¡ã€ã«ãäœæããŠããŸã ãã¹ã¿ãŒ.cmg.ãµã³ãã«ã ååãå€æŽããå¿ èŠããããŸã ãã¹ã¿ãŒ.cfg.ãµã³ã㫠в ãã¹ã¿ãŒ.cfg
mv master.cfg.sample master.cfg
ãããéããŠã¿ãŸããã ãã¹ã¿ãŒ.cfgã ãããŠããããäœã§æ§æãããŠããããèŠãŠã¿ãŸãããã ãã®åŸãç¬èªã®èšå®ãã¡ã€ã«ãäœæããŠã¿ãŸãããã
ãã¹ã¿ãŒ.cfg
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
'git://github.com/buildbot/hello-world.git',
workdir='gitpoller-workdir', branch='master',
pollInterval=300))
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="all",
change_filter=util.ChangeFilter(branch='master'),
treeStableTimer=None,
builderNames=["runtests"]))
c['schedulers'].append(schedulers.ForceScheduler(
name="force",
builderNames=["runtests"]))
factory = util.BuildFactory()
factory.addStep(steps.Git(repourl='git://github.com/buildbot/hello-world.git', mode='incremental'))
factory.addStep(steps.ShellCommand(command=["trial", "hello"],
env={"PYTHONPATH": "."}))
c['builders'] = []
c['builders'].append(
util.BuilderConfig(name="runtests",
workernames=["example-worker"],
factory=factory))
c['services'] = []
c['title'] = "Hello World CI"
c['titleURL'] = "https://buildbot.github.io/hello-world/"
c['buildbotURL'] = "http://localhost:8010/"
c['www'] = dict(port=8010,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}))
c['db'] = {
'db_url' : "sqlite:///state.sqlite",
}
5.1 ãã«ããã¹ã¿ãŒæ§æ
c = BuildmasterConfig = {}
ãã«ããã¹ã¿ãŒæ§æ â èšå®ãã¡ã€ã«ã®åºæ¬èŸæžã æ§æãã¡ã€ã«ã«å«ããå¿
èŠããããŸãã 䜿ããããããããã«ãæ§æã³ãŒãã«ãšã€ãªã¢ã¹ãå°å
¥ãããŠããŸãã ãcãã ã¿ã€ãã«
5.2åŽåè
c['workers'] = [worker.Worker("example-worker", "pass")]
ä»åãæ¡å
ããã®ã¯ã ãã«ããã¹ã¿ãŒ-y ã®ãªã¹ã ã¯ãŒã«ãŒ-sã èªåèªèº« ã¯ãŒã«ãŒ ç§ãã¡ãäœã£ã
5.3 å€æŽãœãŒã¹
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
'git://github.com/buildbot/hello-world.git',
workdir='gitpoller-workdir', branch='master',
pollInterval=300))
ããŒã«ãã å€æŽå Dictionary c ã䜿çšãããšããããžã§ã¯ãã®ãœãŒã¹ ã³ãŒããå«ããªããžããªãããŒãªã³ã°ãããªããžã§ã¯ããé 眮ãããªã¹ãã«ã¢ã¯ã»ã¹ã§ããŸãã ãã®äŸã§ã¯ãç¹å®ã®ééã§ããŒãªã³ã°ããã Git ãªããžããªã䜿çšããŸãã
æåã®åŒæ°ã¯ãªããžããªãžã®ãã¹ã§ãã
äœæ¥ãã£ã¬ã¯ã㪠ã¯æšªã«ãããã©ã«ããŒãžã®ãã¹ãè¡šããŸã ã¯ãŒã«ãŒ- ãã¹ã«å¯Ÿããçžå¯Ÿå€ /home/habr/worker/yourProject/build git ã¯ãªããžããªã®ããŒã«ã« ããŒãžã§ã³ãä¿åããŸãã
ãã©ã³ã ãªããžããªå ã®åŸãã¹ãç¹å®ã®ãã©ã³ããå«ãŸããŠããŸãã
ããŒãªã³ã°éé ãã®åŸã®ç§æ°ãå«ãŸããŸã ãã«ããã¹ã¿ãŒ å€æŽããªãããªããžããªãããŒãªã³ã°ããŸãã
ãããžã§ã¯ãã®ãªããžããªãžã®å€æŽã远跡ããã«ã¯ãããã€ãã®æ¹æ³ããããŸãã
æãç°¡åãªæ¹æ³ã¯ ããŒãªã³ã°ãããã¯æ¬¡ã®ããšãæå³ããŸã ãã«ããã¹ã¿ãŒ ãªããžããªã䜿çšããŠãµãŒããŒãå®æçã«ããŒãªã³ã°ããŸãã ãã ã³ããã ãªããžããªå
ã®å€æŽãåæ ããŠããã ãã«ããã¹ã¿ãŒ å€å°ã®é
ãã䌎ããªããå
éšãªããžã§ã¯ããäœæããŸã å€æŽãã ãããŠãããã€ãã³ããã³ãã©ãŒã«éä¿¡ããŸã ã¹ã±ãžã¥ãŒã©, ããã«ããããããžã§ã¯ãããã«ãããŠãã¹ãããæé ãéå§ãããŸãã ã¯ãŒã«ãŒ-eã ãããã®æé ã®äžã§ç€ºãããã®ã¯ã update ãªããžããªã ãŸãã«ãªã³ ã¯ãŒã«ãŒããã«ããããªããžããªã®ããŒã«ã« ã³ããŒãäœæãããŸãã ãã®ããã»ã¹ã®è©³çŽ°ã«ã€ããŠã¯ã次㮠XNUMX ã€ã®ã»ã¯ã·ã§ã³ã§èª¬æããŸãã (
ãªããžããªãžã®å€æŽã远跡ããããã«æŽç·Žãããæ¹æ³ã¯ããªããžããªããã¹ãããŠãããµãŒããŒããã¡ãã»ãŒãžãçŽæ¥éä¿¡ããããšã§ãã ãã«ããã¹ã¿ãŒ- ãããžã§ã¯ãã®ãœãŒã¹ã³ãŒãã®å€æŽã«ã€ããŠã ãã®å Žåãéçºè ãäœæãããšããã«ã ã³ãããããããžã§ã¯ã ãªããžããªãæã€ãµãŒããŒãã¡ãã»ãŒãžãéä¿¡ããŸãã ãã«ããã¹ã¿ãŒ-yã ãããŠåœŒã¯ä»åºŠã¯ãªããžã§ã¯ããäœæããããšã§ãããååããŸã PBå€æŽãœãŒã¹ã 次ã«ããã®ãªããžã§ã¯ãã¯ã«è»¢éãããŸã ã¹ã±ãžã¥ãŒã©ããã«ããããããžã§ã¯ãããã«ãããŠãã¹ãããæé ãã¢ã¯ãã£ãã«ãªããŸãã ãã®ã¡ãœããã®éèŠãªéšåã¯ã ããã¯-ãªããžããªå ã®ãµãŒã㌠ã¹ã¯ãªããã ã¹ã¯ãªããå 㧠ããã¯-aã次ã®å Žåã®ã¢ã¯ã·ã§ã³ã®åŠçãæ åœããŸãã ã³ããã-eããŠãŒãã£ãªãã£ãåŒã³åºãå¿ èŠããããŸã éä¿¡å€æŽ ãããŠãããã¯ãŒã¯ã¢ãã¬ã¹ãæå®ããŸã ãã«ããã¹ã¿ãŒ-A. ãªãã¹ã³ãããããã¯ãŒã¯ ããŒããæå®ããå¿ èŠããããŸãã PBå€æŽãœãŒã¹. PBå€æŽãœãŒã¹ã¡ãªã¿ã«ã ã¯äžéšã§ã ãã«ããã¹ã¿ãŒ-A. ãã®æ¹æ³ã«ã¯èš±å¯ãå¿ èŠã§ã 管ç人-a ãããžã§ã¯ã ãªããžããªãé 眮ãããŠãããµãŒããŒäžã§ã ãŸããªããžããªã®ããã¯ã¢ãããäœæããå¿ èŠããããŸãã
5.4 ã¹ã±ãžã¥ãŒã©ãŒ
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="all",
change_filter=util.ChangeFilter(branch='master'),
treeStableTimer=None,
builderNames=["runtests"]))
c['schedulers'].append(schedulers.ForceScheduler(
name="force",
builderNames=["runtests"]))
ã¹ã±ãžã¥ãŒã©ãŒ â ããã¯ããããžã§ã¯ãã®ã¢ã»ã³ããªãšãã¹ãã®ãã§ãŒã³å
šäœãéå§ããããªã¬ãŒãšããŠæ©èœããèŠçŽ ã§ãã
èšé²ããããããã®å€æŽ å€æŽå
ãäœæ¥ã®éçšã§å€æãããŸã ãã«ãããã-a ãªããžã§ã¯ããž å€æŽãã ãããŠä»ã§ã¯æ¯å ã·ã§ãã¥ã©ãŒ ãããã«åºã¥ããŠããããžã§ã¯ãã®ãã«ã ããã»ã¹ãéå§ããããã®ãªã¯ãšã¹ããäœæããŸãã ãã ãããããã®ãªã¯ãšã¹ãããã€ãã¥ãŒã«è»¢éããããã決å®ããŸãã ãªããžã§ã¯ã
çŸåšã®äŸã§ã¯ã次ã®ãããªããšãããããŸã ã¹ã±ãžã¥ãŒã©ãŒ 2åäœæãããŸãã ããã«ãããããã«ç¬èªã®ã¿ã€ãããããŸãã
ã·ã³ã°ã«ãã©ã³ãã¹ã±ãžã¥ãŒã© â ã¹ã±ãžã¥ãŒã«ã®äžã§æã人æ°ã®ããã¯ã©ã¹ã® XNUMX ã€ã ãã㯠XNUMX ã€ã®ãã©ã³ããç£èŠãããã®ãã©ã³ãå ã§èšé²ãããå€æŽã«ãã£ãŠããªã¬ãŒãããŸãã å€æŽã確èªããå Žåããã«ã ãªã¯ãšã¹ãã®éä¿¡ãé ãããããšãã§ããŸã (ç¹å¥ãªãã©ã¡ãŒã¿ãŒã§æå®ãããæéã ãé 延ããŸã)ã ããªãŒå®å®ã¿ã€ããŒïŒ 㧠å ã«è¡šç€ºãããã¹ã±ãžã¥ãŒã«ã®ååãèšå®ããŸãã ãã«ãããã-ãŠã§ãã€ã³ã¿ãŒãã§ã€ã¹ã 㧠ãã£ã«ã¿ãŒå€æŽ ãã£ã«ã¿ãŒãèšå®ããããã©ã³ãå ã®å€æŽãééããåŸãã¹ã±ãžã¥ãŒã«ã«æ§ç¯ãªã¯ãšã¹ãã®éä¿¡ãèŠæ±ãããŸãã 㧠ãã«ããŒå ååãèšèŒãããŠãã ãã«ããŒ-aãå°ãåŸã§èšå®ããŸãã ãã®å Žåã®ååã¯ãããžã§ã¯ãåãšåãã«ãªããŸãã ããªãã®ãããžã§ã¯ã.
ãã©ãŒã¹ã¹ã±ãžã¥ãŒã© ãšãŠãåçŽãªããšã ãã®ã¿ã€ãã®ã¹ã±ãžã¥ãŒã«ã¯ãããŠã¹ã®ã¯ãªãã¯ã«ãã£ãŠããªã¬ãŒãããŸã ãã«ãããã-ãŠã§ãã€ã³ã¿ãŒãã§ã€ã¹ã ãã©ã¡ãŒã¿ã®æ¬è³ªã¯æ¬¡ã®ãšããã§ãã ã·ã³ã°ã«ãã©ã³ãã¹ã±ãžã¥ãŒã©.
PSãã®3ã ãããããã圹ã«ç«ã€ãããããªã
å®æç㪠ç¹å®ã®æéã«åºå®ãããé »åºŠã§å®è¡ãããã¹ã±ãžã¥ãŒã«ã§ãã åŒã³åºãã¯æ¬¡ã®ããã«ãªããŸã
from buildbot.plugins import schedulers
nightly = schedulers.Periodic(name="daily",
builderNames=["full-solaris"],
periodicBuildTimer=24*60*60)
c['schedulers'] = [nightly]
5.5 ãã«ããã¡ã¯ããªãŒ
factory = util.BuildFactory()
factory.addStep(steps.Git(repourl='git://github.com/buildbot/hello-world.git', mode='incremental'))
factory.addStep(steps.ShellCommand(command=["trial", "hello"],
env={"PYTHONPATH": "."}))
å®æçãªãã«ãã¿ã€ã㌠ãã®åšæã®æéãç§åäœã§æå®ããŸãã
ãã«ããã¡ã¯ããªãŒ ç¹å®ã®ãäœæããŸã ãã«ãããããš ãã«ã㌠ã«éä¿¡ããŸã ã¯ãŒã«ãŒã 㧠ãã«ããã¡ã¯ããªãŒ åŸãã¹ãæé ã瀺ããŸã ã¯ãŒã«ãŒ-yã ã¡ãœãããåŒã³åºãããšã§ã¹ããããè¿œå ãããŸã è¿œå ã¹ããã
ãã®äŸã§æåã«è¿œå ãããã¹ãããã¯æ¬¡ã®ãšããã§ãã git clean -d -f -f âxããã®åŸ gitãã§ãã¯ã¢ãŠãã ãããã®ã¢ã¯ã·ã§ã³ã¯ãã©ã¡ãŒã¿ã«å«ãŸããŸã æ¹æ³ãæ確ã«èšèŒãããŠããŸããããããã©ã«ãå€ãæ瀺ããŠããŸãã æ°é®®ãªã ãã©ã¡ãŒã¿ ã¢ãŒã='ã€ã³ã¯ãªã¡ã³ã¿ã«' ãã¡ã€ã«ã次ã®ãã£ã¬ã¯ããªããã®ãã®ã§ããããšã瀺ããŸãã ãã§ãã¯ã¢ãŠãããªããžããªããæ¬ èœããŠããéã¯ãå€æŽãããªããŸãŸã«ãªããŸãã
XNUMX çªç®ã«è¿œå ãããã¹ãããã¯ã¹ã¯ãªããã®åŒã³åºãã§ãã ãã©ã€ã¢ã« ãã©ã¡ãŒã¿ä»ã ããã«ã¡ã¯ 暪㫠ã¯ãŒã«ãŒ-a ãã£ã¬ã¯ããªãã /home/habr/worker/yourProject/build ç°å¢å€æ° PATHONPATH=... ã䜿çšãããšãç¬èªã®ã¹ã¯ãªãããäœæããŠãµã€ãã§å®è¡ã§ããŸãã ã¯ãŒã«ãŒ-ãã¹ãŠã®ã¹ããã util.ShellCommandã ãããã®ã¹ã¯ãªããã¯ãªããžããªã«çŽæ¥é 眮ã§ããŸãã ãã®åŸã ãã§ãã¯ã¢ãŠã-e 圌ãã¯é¥ãã ãã /home/habr/worker/yourProject/buildã ãã ãã次㮠XNUMX ã€ã®ããã ããããããŸãã
- ã¯ãŒã«ãŒ ããŒã䜿çšããŠäœæããå¿
èŠããããŸã
--umask åŸã®å®è¡æš©éããããã¯ããªãããã«ãããã ãã§ãã¯ã¢ãŠã-ãããŠã - ã« git pushãããã®ã¹ã¯ãªããã® -e ããããã£ãæå®ããå¿ èŠããããŸã å®è¡å¯èœããã§åŸã§ ãã§ãã¯ã¢ãŠã-e ã¯ãGit ã¹ã¯ãªãããå®è¡ããæš©å©ã倱ããŸããã§ããã
5.6ãã«ããŒ
c['builders'] = []
c['builders'].append(util.BuilderConfig(name="runtests",
workernames=["example-worker"],
factory=factory))
ãšã¯äœãã«ã€ã㊠ãã«ã㌠èšããã
c['builders'] = []
c['builders'].append(util.BuilderConfig(name="yourProject",
workernames=["yourWorkerName"],
factory=factory))
次ã«ãã©ã¡ãŒã¿ã«ã€ããŠèª¬æããŸã ãã«ããŒæ§æ.
å ååãæå®ããŸã ãã«ããŒ-a. ããã§ååãä»ããŸãã ããªãã®ãããžã§ã¯ãã ããã¯ã ã¯ãŒã«ãŒ- ãŸãã«ãã®ãã¹ãäœæãããŸã /home/habr/worker/yourProject/build. ã·ã§ãã¥ã©ãŒ æ¢ããŠãã ãã«ã㌠ãã®ååã ãã§ã
åŽåè å ã·ãŒããå«ãŸããŠããŸã ã¯ãŒã«ãŒ-sã ãããããè¿œå ããå¿ èŠããããŸã c['åŽåè '].
å·¥å Ž - ç¹å®ã® ãã«ããããã«é¢é£ä»ããããŠããŸã ãã«ããŒã 圌ã¯ç©äœãéããŸã ãã«ã Ма ã¯ãŒã«ãŒ ãã®ææžã«å«ãŸãããã¹ãŠã®æé ãå®äºããã«ã¯ ãã«ã-ãããŠã
6. ç¬èªã®æ§æã®äŸ
ããã¯ãç§ãå®è£
ããããšãææ¡ãããããžã§ã¯ã ã¢ãŒããã¯ãã£ã®äŸã§ãã ãã«ãããã
.
ããŒãžã§ã³ç®¡çã·ã¹ãã ãšããŠäœ¿çšããŸã SVNã ãªããžããªèªäœã¯ãããçš®ã®ã¯ã©ãŠãã«é
眮ãããŸãã ãã®ã¯ã©ãŠãã®ã¢ãã¬ã¹ã¯æ¬¡ã®ãšããã§ã
ãã«ããã¹ã¿ãŒ О ã¯ãŒã«ãŒ åããã¹ãäžã§å®è¡ãã ãããžã§ã¯ã.ãã¹ã .ãã«ããã¹ã¿ãŒ ãã¡ã€ã«ããã©ã«ããŒã«ä¿åããŸã /ããŒã /ãã/ãã¹ã¿ãŒ. ã¯ãŒã«ãŒ 次ã®ãã¹ã«ä¿åãããŸã /ããŒã /ãã/ã¯ãŒã«ãŒã ããã»ã¹éä¿¡ ãã«ããã¹ã¿ãŒ-aãš ã¯ãŒã«ãŒ-a ã¯ãããã³ã«ã«åŸã£ãŠããŒã 4000 çµç±ã§å®è¡ãããŸã ãã«ãããã-ããã€ãŸã ãpbã ãããã³ã«ã
ã¿ãŒã²ãã ãããžã§ã¯ãã¯ãã¹ãŠ Python ã§æžãããŠããŸãã ã¿ã¹ã¯ã¯ãå€æŽã远跡ããå®è¡å¯èœãã¡ã€ã«ãäœæããããã¥ã¡ã³ããçæãããã¹ããå®æœããããšã§ãã 倱æããå Žåããã¹ãŠã®éçºè ã¯ãã¢ã¯ã·ã§ã³ã倱æããããšã瀺ãã¡ãã»ãŒãžãé»åã¡ãŒã«ã§éä¿¡ããå¿ èŠããããŸãã
ãŠã§ã衚瀺 ãã«ãããã ããŒã80ã«æ¥ç¶ããŸã ãããžã§ã¯ã.ãã¹ãã Apatchãã€ã³ã¹ããŒã«ããå¿ èŠã¯ãããŸããã å³æžé€šã®äžéšãšã㊠ãããã ãã§ã«WebãµãŒããŒãååšããŠããã ãã«ãããã ããã䜿çšããŸãã
å éšæ å ±ãä¿åãããã ãã«ãããã бÑЎеЌОÑпПлÑзПваÑÑ sqlite.
ã¡ãŒã«éä¿¡ã«ã¯ãã¹ããå¿ èŠã§ã smtp.your.domain - ã¡ãŒã«ããæçŽãéä¿¡ã§ããããã«ãªããŸã [ã¡ãŒã«ä¿è·] èªèšŒãªãã§ã ãã¹ãäžã§ããSMTP è°äºé²ã¯ãã¹ã 1025 ã§å¯©çãããŸãã
ãã®ããã»ã¹ã«ã¯ XNUMX 人ãé¢äžããŸãã 管ç人 О userã 管çè ã管çãã ãã«ããããã ãŠãŒã¶ãŒã¯ã³ããããã人ã§ã ã³ããã-sã
å®è¡å¯èœãã¡ã€ã«ã¯æ¬¡ã®ããã«çæãããŸãã pyã€ã³ã¹ããŒã©ãŒã ããã¥ã¡ã³ãã¯æ¬¡ã®æ¹æ³ã§çæãããŸãã ããã·ã²ã³.
ãã®ã¢ãŒããã¯ãã£ã«ã€ããŠã¯ã次ã®ããã«æžããŸããã ãã¹ã¿ãŒ.cfg:
ãã¹ã¿ãŒ.cfg
import os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters
c= BuildmasterConfig ={}
c['workers'] = [ worker.Worker('yourWorkerName', 'password') ]
c['protocols'] = {'pb': {'port': 4000}}
svn_poller = changes.SVNPoller(repourl="https://svn.host/svn/yourProject/trunk",
svnuser="user",
svnpasswd="password",
pollinterval=60,
split_file=util.svn.split_file_alwaystrunk
)
c['change_source'] = svn_poller
hourlyscheduler = schedulers.SingleBranchScheduler(
name="your-project-schedulers",
change_filter=util.ChangeFilter(branch=None),
builderNames=["yourProject"],
properties = {'owner': 'admin'}
)
c['schedulers'] = [hourlyscheduler]
checkout = steps.SVN(repourl='https://svn.host/svn/yourProject/trunk',
mode='full',
method='fresh',
username="user",
password="password",
haltOnFailure=True)
projectHost_build = util.BuildFactory()
cleanProject = steps.ShellCommand(name="Clean",
command=["buildbot/worker_linux/pyinstaller_project", "clean"]
)
buildProject = steps.ShellCommand(name="Build",
command=["buildbot/worker_linux/pyinstaller_project", "build"]
)
doxyProject = steps.ShellCommand(name="Update Docs",
command=["buildbot/worker_linux/gendoc", []]
)
testProject = steps.ShellCommand(name="Tests",
command=["python","tests/utest.py"],
env={'PYTHONPATH': '.'}
)
projectHost_build.addStep(checkout)
projectHost_build.addStep(cleanProject)
projectHost_build.addStep(buildProject)
projectHost_build.addStep(doxyProject)
projectHost_build.addStep(testProject)
c['builders'] = [
util.BuilderConfig(name="yourProject", workername='yourWorkerName', factory=projectHost_build)
]
template_html=u'''
<h4>СÑаÑÑÑ Ð¿ÐŸÑÑÑПеММПгП ÑелОза: {{ summary }}</h4>
<p>ÐÑпПлÑзÑеЌÑй ÑеÑÐ²ÐžÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑаеМОÑ: {{ workername }}</p>
<p>ÐÑПекÑ: {{ projects }}</p>
<p>ÐÐ»Ñ ÑПгП ÑÑП Ð±Ñ Ð¿ÐŸÑЌПÑÑеÑÑ ÐžÐœÑеÑÑÐµÐ¹Ñ ÑпÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿ÑПйЎОÑе пП ÑÑÑлке: {{ buildbot_url }}</p>
<p>ÐÐ»Ñ ÑПгП ÑÑП Ð±Ñ Ð¿ÐŸÑЌПÑÑеÑÑ ÑезÑлÑÑÐ°Ñ ÑбПÑкО пÑПйЎОÑе пП ÑÑÑлке: {{ build_url }}</p>
<p>ÐÑпПлÑзÑÑ WinSCP ЌПжМП пПЎклÑÑОÑÑÑÑ Ðº ÑеÑвеÑÑ c ip:xxx.xx.xxx.xx. ÐÐŸÐ¹ÐŽÑ Ð¿ÐŸÐŽ habr/password, забÑаÑÑ ÑПбÑаММÑй executable Ñайл Ñ ÐŽÐžÑекÑПÑОО ~/worker/yourProject/build/dist.</p>
<p><b>ÐПÑÑÑПеМОе бÑлП пÑПОзвеЎеМП ÑеÑез Buildbot</b></p>
'''
sendMessageToAll = reporters.MailNotifier(fromaddr="[email protected]",
sendToInterestedUsers=True,
lookup="your.domain",
relayhost="smtp.your.domain",
smtpPort=1025,
mode="warnings",
extraRecipients=['[email protected]'],
messageFormatter=reporters.MessageFormatter(
template=template_html,
template_type='html',
wantProperties=True,
wantSteps=True)
)
c['services'] = [sendMessageToAll]
c['title'] = "The process of bulding"
c['titleURL'] = "http://project.host:80/"
c['buildbotURL'] = "http://project.host"
c['www'] = dict(port=80,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}))
c['db'] = {
'db_url' : "sqlite:///state.sqlite"
}
ãŸãå¿
èŠãªã®ã¯
次ã®ã¹ãããã¯ãµãŒãã¹ãéå§ããããšã§ã ãã«ããã¹ã¿ãŒãã
sudo buildbot start /home/habr/master
次ã«ãµãŒãã¹ãéå§ããŸã ã¯ãŒã«ãŒ-a
buildbot-worker start /home/habr/worker
æºåãã§ããŠïŒ ä» ãã«ãããã å€æŽã远跡ããŠããªã¬ãŒããŸã ã³ããã-y 㧠SVNãäžèšã®ã¢ãŒããã¯ãã£ã§ãããžã§ã¯ããæ§ç¯ããŠãã¹ãããæé ãå®è¡ããŸãã
以äžã«äžèšã®ç¹åŸŽãããã€ã説æããŸã master.cfgã
6.1 master.cfg ã«åããéäž
ç§ã®ããšãæžããªãã ãã¹ã¿ãŒ.cfg ãšã©ãŒãå€ãçºçããããããã°ãã¡ã€ã«ã®èªã¿åããå¿
èŠã«ãªããŸãã ãšããŠä¿åãããŸã ãã«ããã¹ã¿ãŒ-ec 絶察ãã¹ /home/habr/master/twistd.logããããŠæšªã« ã¯ãŒã«ãŒ-a 絶察ãã¹ä»ã /home/habr/worker/twistd.logã ãšã©ãŒãèªãã§ä¿®æ£ããã«ã¯ããµãŒãã¹ãåèµ·åããå¿
èŠããããŸãã ãã«ããã¹ã¿ãŒ-a. ãã®æ¹æ³ã¯æ¬¡ã®ãšããã§ãã
sudo buildbot stop /home/habr/master
sudo buildbot upgrade-master /home/habr/master
sudo buildbot start /home/habr/master
6.2 svn ã®æäœ
svn_poller = changes.SVNPoller(repourl="https://svn.host/svn/yourProject/trunk",
svnuser="user",
svnpasswd="password",
pollinterval=60,
split_file=util.svn.split_file_alwaystrunk
)
c['change_source'] = svn_poller
hourlyscheduler = schedulers.SingleBranchScheduler(
name="your-project-schedulers",
change_filter=util.ChangeFilter(branch=None),
builderNames=["yourProject"],
properties = {'owner': 'admin'}
)
c['schedulers'] = [hourlyscheduler]
checkout = steps.SVN(repourl='https://svn.host/svn/yourProject/trunk',
mode='full',
method='fresh',
username="user",
password="password",
haltOnFailure=True)
ãŸããèŠãŠã¿ãŸããã svn_pollerã ããã¯äŸç¶ãšããŠåãã€ã³ã¿ãŒãã§ã€ã¹ã§ãããXNUMX åã« XNUMX åå®æçã«ãªããžããªãããŒãªã³ã°ããŸãã ãã®å Žå svn_poller ãã©ã³ãã«ã®ã¿ã¢ã¯ã»ã¹ããŸã ãã©ã³ã¯ã è¬ã®ãã©ã¡ãŒã¿ split_file=util.svn.split_file_alwaystrunk ã«ãŒã«ãèšå®ããŸã: ãã©ã«ããŒæ§é ãåå²ããæ¹æ³ SVN æã®äžã«ã 圌ã¯ãŸãããããã«çžå¯Ÿãã¹ãæäŸããŸãã ãã®é çªã§ Split_file_alwaystrunk ãªããžããªã«å«ãŸãããã®ã®ã¿ãæå®ããããšã§ããã»ã¹ãç°¡ç¥åããŸã ãã©ã³ã¯.
Ð ã¹ã±ãžã¥ãŒã©ãŒ 衚瀺ãããŸã ãã£ã«ã¿ãŒå€æŽèª°ãèŠãŸãã ãªã ãã©ã³ããããã«é¢é£ä»ããŸã ãã©ã³ã¯ ç¹å®ã®é¢é£ä»ãã«åŸã£ãŠã Split_file_alwaystrunkã å€åãžã®å¯Ÿå¿ ãã©ã³ã¯ãçºå£² ãã«ã㌠ååä»ã ããªãã®ãããžã§ã¯ã.
ãããã㣠ããã§ã¯ã管çè ãããã»ã¹ã®ææè ãšããŠãã«ãããã³ãã¹ãçµæã®ã¡ãŒãªã³ã° ãªã¹ããåä¿¡ããããã«å¿ èŠã§ãã
æé ãã«ã-a ãã§ãã¯ã¢ãŠã ããŒã«ã« ããŒãžã§ã³ã®ãªããžããªã«ãããã¡ã€ã«ãå®å šã«åé€ã§ããŸã ã¯ãŒã«ãŒ-A. ãããŠããã¹ãŠãå®è¡ããŸã svn updateã ã¢ãŒãã¯ãã©ã¡ãŒã¿ãéããŠèšå®ãããŸãã ã¢ãŒã=ãã«, ã¡ãœãã=ãã¬ãã·ã¥ã ãã©ã¡ãŒã¿ åæ¢ãªã³ããŒã« ãã svn update ãšã©ãŒãçºçããŠå®è¡ããããšããã以äžã®ã¢ã¯ã·ã§ã³ã¯æå³ããªãããããã«ããšãã¹ãã®ããã»ã¹å šäœãäžæåæ¢ãããå¿ èŠããããŸãã
6.3 ããªããžã®æçŽ: èšè ã«ã¯å®£èšããæš©éããã
èšè
ãç¥ãããã¡ãŒã«ã§éä¿¡ãããµãŒãã¹ã§ãã
template_html=u'''
<h4>СÑаÑÑÑ Ð¿ÐŸÑÑÑПеММПгП ÑелОза: {{ summary }}</h4>
<p>ÐÑпПлÑзÑеЌÑй ÑеÑÐ²ÐžÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑаеМОÑ: {{ workername }}</p>
<p>ÐÑПекÑ: {{ projects }}</p>
<p>ÐÐ»Ñ ÑПгП ÑÑП Ð±Ñ Ð¿ÐŸÑЌПÑÑеÑÑ ÐžÐœÑеÑÑÐµÐ¹Ñ ÑпÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿ÑПйЎОÑе пП ÑÑÑлке: {{ buildbot_url }}</p>
<p>ÐÐ»Ñ ÑПгП ÑÑП Ð±Ñ Ð¿ÐŸÑЌПÑÑеÑÑ ÑезÑлÑÑÐ°Ñ ÑбПÑкО пÑПйЎОÑе пП ÑÑÑлке: {{ build_url }}</p>
<p>ÐÑпПлÑзÑÑ WinSCP ЌПжМП пПЎклÑÑОÑÑÑÑ Ðº ÑеÑвеÑÑ c ip:xxx.xx.xxx.xx. ÐÐŸÐ¹ÐŽÑ Ð¿ÐŸÐŽ habr/password, забÑаÑÑ ÑПбÑаММÑй executable Ñайл Ñ ÐŽÐžÑекÑПÑОО ~/worker/yourProject/build/dist.</p>
<p><b>ÐПÑÑÑПеМОе бÑлП пÑПОзвеЎеМП ÑеÑез Buildbot</b></p>
'''
sendMessageToAll = reporters.MailNotifier(fromaddr="[email protected]",
sendToInterestedUsers=True,
lookup="your.domain",
relayhost="smtp.your.domain",
smtpPort=1025,
mode="warnings",
extraRecipients=['[email protected]'],
messageFormatter=reporters.MessageFormatter(
template=template_html,
template_type='html',
wantProperties=True,
wantSteps=True)
)
c['services'] = [sendMessageToAll]
圌ã¯ã¡ãã»ãŒãžãéãããšãã§ãã
MailNotifier é»åã¡ãŒã«ã䜿çšããŠéç¥ãéä¿¡ããŸãã
ãã³ãã¬ãŒã_html ãã¥ãŒã¹ã¬ã¿ãŒã®ããã¹ã ãã³ãã¬ãŒããèšå®ããŸãã HTML ã¯ããŒã¯ã¢ããã®äœæã«äœ¿çšãããŸãã ãšã³ãžã³ã«ãã£ãŠæ¹é ããã
MailNotifier ã«ã¯æ¬¡ã®åŒæ°ãå«ãŸããŸãã
fromaddr â å šå¡ããã¥ãŒã¹ã¬ã¿ãŒãåãåãã¢ãã¬ã¹ã
èå³ã®ãããŠãŒã¶ãŒã«éä¿¡=True ã¯ãäœæããææè ãšãŠãŒã¶ãŒã«ã¡ãã»ãŒãžãéä¿¡ããŸãã ã³ããã.
æ€çŽ¢ â ãã¥ãŒã¹ã¬ã¿ãŒãåä¿¡ãããŠãŒã¶ãŒã®ååã«è¿œå ããå¿ èŠããããµãã£ãã¯ã¹ã ãã㧠管ç人 ãŠãŒã¶ãŒããã®ã¢ãã¬ã¹ã§ãã¥ãŒã¹ã¬ã¿ãŒãåãåãæ¹æ³ [ã¡ãŒã«ä¿è·].
ãªã¬ãŒãã¹ã ãµãŒããŒãéãããŠãããã¹ãåãæå®ããŸã SMTP smptããŒã ãªãã¹ã³ããããŒãçªå·ãæå®ããŸã SMTP ãµãŒãã
ã¢ãŒã = "èŠå" å°ãªããšã XNUMX ã€ã®ã¹ããããããå Žåã«ã®ã¿éµéãè¡ãå¿ èŠããããšè¿°ã¹ãŠããŸã ãã«ã-aãã¹ããŒã¿ã¹å€±æãŸãã¯èŠåã§çµäºããŸããã æåããå Žåããã¥ãŒã¹ã¬ã¿ãŒãéä¿¡ããå¿ èŠã¯ãããŸããã
è¿œå åä¿¡è ææè ããã³éµäŸ¿ç©ã®å®è¡è ã«å ããŠãéµéç©ãéä¿¡ãããã¹ã人ç©ã®ãªã¹ããå«ãŸããŸãã ã³ããã.
ã¡ãã»ãŒãžãã©ãŒããã¿ ã¡ãã»ãŒãžåœ¢åŒããã®ãã³ãã¬ãŒããããã³ããå©çšå¯èœãªå€æ°ã®ã»ãããæå®ãããªããžã§ã¯ãã§ãã ãžã³ãžã£2ã ãªã©ã®ãªãã·ã§ã³ wantProperties=True О wantSteps=True ãã®å©çšå¯èœãªå€æ°ã®ã»ãããå®çŸ©ããŸãã
with['services']=[sendMessageToAll] ãµãŒãã¹ã®ãªã¹ããæäŸããŸãããã®ãã¡ã® XNUMX ã€ã¯ã ã¬ããŒã¿ãŒ.
ãã£ãïŒ ããã§ãšã
ç§ãã¡ã¯ç¬èªã®æ§æãäœæãããããå¯èœãªæ©èœã確èªããŸããã ãã«ããããã ããã¯ããããžã§ã¯ãã®äœæã«ãã®ããŒã«ãå¿ èŠãã©ãããç解ããã®ã«ååã ãšæããŸãã 圌ã«èå³ããããŸããïŒ ããã¯åœ¹ã«ç«ã¡ãŸããïŒ åœŒã¯äžç·ã«ä»äºãããã®ãå¿«é©ã§ããïŒ ããããã°ãç§ã¯ãã®èšäºãç¡é§ã«æžããŠããããã§ã¯ãããŸããã
ãããŠããã«ã ãããã§ãã·ã§ãã«ã³ãã¥ããã£ã«æŽ»çšããŠããããã ãã«ããããã®ç¯å²ãåºããªããããã¥ã¢ã«ã翻蚳ãããäŸãããã«å¢ããŸããã
ãæž
èŽããããšãããããŸããã 幞éãã
åºæïŒ habr.com