@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3/**
4 * Execute a build target.
5 */
6final class HarbormasterTargetWorker extends HarbormasterWorker {
7
8 public function getRequiredLeaseTime() {
9 // This worker performs actual build work, which may involve a long wait
10 // on external systems.
11 return phutil_units('24 hours in seconds');
12 }
13
14 public function renderForDisplay(PhabricatorUser $viewer) {
15 try {
16 $target = $this->loadBuildTarget();
17 } catch (Exception $ex) {
18 return null;
19 }
20
21 return $viewer->renderHandle($target->getPHID());
22 }
23
24 private function loadBuildTarget() {
25 $data = $this->getTaskData();
26 $id = idx($data, 'targetID');
27
28 $target = id(new HarbormasterBuildTargetQuery())
29 ->withIDs(array($id))
30 ->setViewer($this->getViewer())
31 ->needBuildSteps(true)
32 ->executeOne();
33
34 if (!$target) {
35 throw new PhabricatorWorkerPermanentFailureException(
36 pht(
37 'Bad build target ID "%d".',
38 $id));
39 }
40
41 return $target;
42 }
43
44 protected function doWork() {
45 $target = $this->loadBuildTarget();
46 $build = $target->getBuild();
47 $viewer = $this->getViewer();
48
49 // If this is the first time we're starting work on this target, mark the
50 // current time as the start time. If the target yields or waits, we may
51 // end up here again later, so we don't want to overwrite the start time if
52 // we already have a value.
53 if (!$target->getDateStarted()) {
54 $target->setDateStarted(PhabricatorTime::getNow());
55 }
56
57 try {
58 if ($target->getBuildGeneration() !== $build->getBuildGeneration()) {
59 throw new HarbormasterBuildAbortedException();
60 }
61
62 $status_pending = HarbormasterBuildTarget::STATUS_PENDING;
63 if ($target->getTargetStatus() == $status_pending) {
64 $target->setTargetStatus(HarbormasterBuildTarget::STATUS_BUILDING);
65 $target->save();
66 }
67
68 $implementation = $target->getImplementation();
69 $implementation->setCurrentWorkerTaskID($this->getCurrentWorkerTaskID());
70 $implementation->execute($build, $target);
71
72 $next_status = HarbormasterBuildTarget::STATUS_PASSED;
73 if ($implementation->shouldWaitForMessage($target)) {
74 $next_status = HarbormasterBuildTarget::STATUS_WAITING;
75 }
76
77 $target->setTargetStatus($next_status);
78
79 if ($target->isComplete()) {
80 $target->setDateCompleted(PhabricatorTime::getNow());
81 }
82
83 $target->save();
84 } catch (PhabricatorWorkerYieldException $ex) {
85 // If the target wants to yield, let that escape without further
86 // processing. We'll resume after the task retries.
87 throw $ex;
88 } catch (HarbormasterBuildFailureException $ex) {
89 // A build step wants to fail explicitly.
90 $target->setTargetStatus(HarbormasterBuildTarget::STATUS_FAILED);
91 $target->setDateCompleted(PhabricatorTime::getNow());
92 $target->save();
93 } catch (HarbormasterBuildAbortedException $ex) {
94 // A build step is aborting because the build has been restarted.
95 $target->setTargetStatus(HarbormasterBuildTarget::STATUS_ABORTED);
96 $target->setDateCompleted(PhabricatorTime::getNow());
97 $target->save();
98 } catch (Exception $ex) {
99 try {
100 $log = $target->newLog('core', 'exception')
101 ->append($ex)
102 ->closeBuildLog();
103 } catch (Exception $log_ex) {
104 phlog($log_ex);
105 }
106
107 $target->setTargetStatus(HarbormasterBuildTarget::STATUS_FAILED);
108 $target->setDateCompleted(time());
109 $target->save();
110 }
111
112 id(new HarbormasterBuildEngine())
113 ->setViewer($viewer)
114 ->setBuild($build)
115 ->continueBuild();
116 }
117
118}