@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 * Records a push to a hosted repository. This allows us to store metadata
5 * about who pushed commits, when, and from where. We can also record the
6 * history of branches and tags, which is not normally persisted outside of
7 * the reflog.
8 *
9 * This log is written by commit hooks installed into hosted repositories.
10 * See @{class:DiffusionCommitHookEngine}.
11 */
12final class PhabricatorRepositoryPushLog
13 extends PhabricatorRepositoryDAO
14 implements PhabricatorPolicyInterface {
15
16 const REFTYPE_BRANCH = 'branch';
17 const REFTYPE_TAG = 'tag';
18 const REFTYPE_BOOKMARK = 'bookmark';
19 const REFTYPE_COMMIT = 'commit';
20 const REFTYPE_REF = 'ref';
21 const REFTYPE_MAINTENANCE = 'maintenance';
22
23 const CHANGEFLAG_ADD = 1;
24 const CHANGEFLAG_DELETE = 2;
25 const CHANGEFLAG_APPEND = 4;
26 const CHANGEFLAG_REWRITE = 8;
27 const CHANGEFLAG_DANGEROUS = 16;
28 const CHANGEFLAG_ENORMOUS = 32;
29 const CHANGEFLAG_OVERSIZED = 64;
30 const CHANGEFLAG_TOUCHES = 128;
31 const CHANGEFLAG_MAINTENANCE = 256;
32
33 const REJECT_ACCEPT = 0;
34 const REJECT_DANGEROUS = 1;
35 const REJECT_HERALD = 2;
36 const REJECT_EXTERNAL = 3;
37 const REJECT_BROKEN = 4;
38 const REJECT_ENORMOUS = 5;
39 const REJECT_OVERSIZED = 6;
40 const REJECT_TOUCHES = 7;
41
42 protected $repositoryPHID;
43 protected $epoch;
44 protected $pusherPHID;
45 protected $pushEventPHID;
46 protected $devicePHID;
47 protected $refType;
48 protected $refNameHash;
49 protected $refNameRaw;
50 protected $refNameEncoding;
51 protected $refOld;
52 protected $refNew;
53 protected $mergeBase;
54 protected $changeFlags;
55
56 private $dangerousChangeDescription = self::ATTACHABLE;
57 private $pushEvent = self::ATTACHABLE;
58 private $repository = self::ATTACHABLE;
59
60 public static function initializeNewLog(PhabricatorUser $viewer) {
61 return id(new PhabricatorRepositoryPushLog())
62 ->setPusherPHID($viewer->getPHID());
63 }
64
65 public static function getFlagDisplayNames() {
66 return array(
67 self::CHANGEFLAG_ADD => pht('Create'),
68 self::CHANGEFLAG_DELETE => pht('Delete'),
69 self::CHANGEFLAG_APPEND => pht('Append'),
70 self::CHANGEFLAG_REWRITE => pht('Rewrite'),
71 self::CHANGEFLAG_DANGEROUS => pht('Dangerous'),
72 self::CHANGEFLAG_ENORMOUS => pht('Enormous'),
73 self::CHANGEFLAG_OVERSIZED => pht('Oversized'),
74 self::CHANGEFLAG_TOUCHES => pht('Touches Too Many Paths'),
75 self::CHANGEFLAG_MAINTENANCE => pht('Maintenance'),
76 );
77 }
78
79 public static function getRejectCodeDisplayNames() {
80 return array(
81 self::REJECT_ACCEPT => pht('Accepted'),
82 self::REJECT_DANGEROUS => pht('Rejected: Dangerous'),
83 self::REJECT_HERALD => pht('Rejected: Herald'),
84 self::REJECT_EXTERNAL => pht('Rejected: External Hook'),
85 self::REJECT_BROKEN => pht('Rejected: Broken'),
86 self::REJECT_ENORMOUS => pht('Rejected: Enormous'),
87 self::REJECT_OVERSIZED => pht('Rejected: Oversized File'),
88 self::REJECT_TOUCHES => pht('Rejected: Touches Too Many Paths'),
89 );
90 }
91
92 public static function getHeraldChangeFlagConditionOptions() {
93 return array(
94 self::CHANGEFLAG_ADD =>
95 pht('change creates ref'),
96 self::CHANGEFLAG_DELETE =>
97 pht('change deletes ref'),
98 self::CHANGEFLAG_REWRITE =>
99 pht('change rewrites ref'),
100 self::CHANGEFLAG_DANGEROUS =>
101 pht('dangerous change'),
102 );
103 }
104
105 protected function getConfiguration() {
106 return array(
107 self::CONFIG_AUX_PHID => true,
108 self::CONFIG_TIMESTAMPS => false,
109 self::CONFIG_BINARY => array(
110 'refNameRaw' => true,
111 ),
112 self::CONFIG_COLUMN_SCHEMA => array(
113 'refType' => 'text12',
114 'refNameHash' => 'bytes12?',
115 'refNameRaw' => 'bytes?',
116 'refNameEncoding' => 'text16?',
117 'refOld' => 'text40?',
118 'refNew' => 'text40',
119 'mergeBase' => 'text40?',
120 'changeFlags' => 'uint32',
121 'devicePHID' => 'phid?',
122 ),
123 self::CONFIG_KEY_SCHEMA => array(
124 'key_repository' => array(
125 'columns' => array('repositoryPHID'),
126 ),
127 'key_ref' => array(
128 'columns' => array('repositoryPHID', 'refNew'),
129 ),
130 'key_name' => array(
131 'columns' => array('repositoryPHID', 'refNameHash'),
132 ),
133 'key_event' => array(
134 'columns' => array('pushEventPHID'),
135 ),
136 'key_pusher' => array(
137 'columns' => array('pusherPHID'),
138 ),
139 'key_epoch' => array(
140 'columns' => array('epoch'),
141 ),
142 ),
143 ) + parent::getConfiguration();
144 }
145
146 public function generatePHID() {
147 return PhabricatorPHID::generateNewPHID(
148 PhabricatorRepositoryPushLogPHIDType::TYPECONST);
149 }
150
151 public function attachPushEvent(PhabricatorRepositoryPushEvent $push_event) {
152 $this->pushEvent = $push_event;
153 return $this;
154 }
155
156 public function getPushEvent() {
157 return $this->assertAttached($this->pushEvent);
158 }
159
160 public function getRefName() {
161 return $this->getUTF8StringFromStorage(
162 $this->getRefNameRaw(),
163 $this->getRefNameEncoding());
164 }
165
166 public function setRefName($ref_raw) {
167 $this->setRefNameRaw($ref_raw);
168 $this->setRefNameHash(PhabricatorHash::digestForIndex($ref_raw));
169 $this->setRefNameEncoding($this->detectEncodingForStorage($ref_raw));
170
171 return $this;
172 }
173
174 public function getRefOldShort() {
175 if ($this->getRepository()->isSVN()) {
176 return $this->getRefOld();
177 }
178 return substr($this->getRefOld(), 0, 12);
179 }
180
181 public function getRefNewShort() {
182 if ($this->getRepository()->isSVN()) {
183 return $this->getRefNew();
184 }
185 return substr($this->getRefNew(), 0, 12);
186 }
187
188 public function hasChangeFlags($mask) {
189 return ($this->changeFlags & $mask);
190 }
191
192 public function attachDangerousChangeDescription($description) {
193 $this->dangerousChangeDescription = $description;
194 return $this;
195 }
196
197 public function getDangerousChangeDescription() {
198 return $this->assertAttached($this->dangerousChangeDescription);
199 }
200
201 public function attachRepository(PhabricatorRepository $repository) {
202 // NOTE: Some gymnastics around this because of object construction order
203 // in the hook engine. Particularly, web build the logs before we build
204 // their push event.
205 $this->repository = $repository;
206 return $this;
207 }
208
209 public function getRepository() {
210 if ($this->repository == self::ATTACHABLE) {
211 return $this->getPushEvent()->getRepository();
212 }
213 return $this->assertAttached($this->repository);
214 }
215
216
217/* -( PhabricatorPolicyInterface )----------------------------------------- */
218
219
220 public function getCapabilities() {
221 return array(
222 PhabricatorPolicyCapability::CAN_VIEW,
223 );
224 }
225
226 public function getPolicy($capability) {
227 // NOTE: We're passing through the repository rather than the push event
228 // mostly because we need to do policy checks in Herald before we create
229 // the event. The two approaches are equivalent in practice.
230 return $this->getRepository()->getPolicy($capability);
231 }
232
233 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
234 return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
235 }
236
237 public function describeAutomaticCapability($capability) {
238 return pht(
239 "A repository's push logs are visible to users who can see the ".
240 "repository.");
241 }
242
243}