Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / repository / storage / PhabricatorRepositoryPushLog.php
blob58f1dc6001b5a3b6701e3ed744d19d6f7687e520
1 <?php
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.
9 * This log is written by commit hooks installed into hosted repositories.
10 * See @{class:DiffusionCommitHookEngine}.
12 final class PhabricatorRepositoryPushLog
13 extends PhabricatorRepositoryDAO
14 implements PhabricatorPolicyInterface {
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';
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;
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;
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;
56 private $dangerousChangeDescription = self::ATTACHABLE;
57 private $pushEvent = self::ATTACHABLE;
58 private $repository = self::ATTACHABLE;
60 public static function initializeNewLog(PhabricatorUser $viewer) {
61 return id(new PhabricatorRepositoryPushLog())
62 ->setPusherPHID($viewer->getPHID());
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'),
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'),
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'),
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,
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?',
123 self::CONFIG_KEY_SCHEMA => array(
124 'key_repository' => array(
125 'columns' => array('repositoryPHID'),
127 'key_ref' => array(
128 'columns' => array('repositoryPHID', 'refNew'),
130 'key_name' => array(
131 'columns' => array('repositoryPHID', 'refNameHash'),
133 'key_event' => array(
134 'columns' => array('pushEventPHID'),
136 'key_pusher' => array(
137 'columns' => array('pusherPHID'),
139 'key_epoch' => array(
140 'columns' => array('epoch'),
143 ) + parent::getConfiguration();
146 public function generatePHID() {
147 return PhabricatorPHID::generateNewPHID(
148 PhabricatorRepositoryPushLogPHIDType::TYPECONST);
151 public function attachPushEvent(PhabricatorRepositoryPushEvent $push_event) {
152 $this->pushEvent = $push_event;
153 return $this;
156 public function getPushEvent() {
157 return $this->assertAttached($this->pushEvent);
160 public function getRefName() {
161 if ($this->getRefNameRaw() === null) {
162 return null;
164 return $this->getUTF8StringFromStorage(
165 $this->getRefNameRaw(),
166 $this->getRefNameEncoding());
169 public function setRefName($ref_raw) {
170 $this->setRefNameRaw($ref_raw);
171 $this->setRefNameHash(PhabricatorHash::digestForIndex($ref_raw));
172 $this->setRefNameEncoding($this->detectEncodingForStorage($ref_raw));
174 return $this;
177 public function getRefOldShort() {
178 if ($this->getRepository()->isSVN()) {
179 return $this->getRefOld();
181 if ($this->getRefOld() === null) {
182 return null;
184 return substr($this->getRefOld(), 0, 12);
187 public function getRefNewShort() {
188 if ($this->getRepository()->isSVN()) {
189 return $this->getRefNew();
191 return substr($this->getRefNew(), 0, 12);
194 public function hasChangeFlags($mask) {
195 return ($this->changeFlags & $mask);
198 public function attachDangerousChangeDescription($description) {
199 $this->dangerousChangeDescription = $description;
200 return $this;
203 public function getDangerousChangeDescription() {
204 return $this->assertAttached($this->dangerousChangeDescription);
207 public function attachRepository(PhabricatorRepository $repository) {
208 // NOTE: Some gymnastics around this because of object construction order
209 // in the hook engine. Particularly, web build the logs before we build
210 // their push event.
211 $this->repository = $repository;
212 return $this;
215 public function getRepository() {
216 if ($this->repository == self::ATTACHABLE) {
217 return $this->getPushEvent()->getRepository();
219 return $this->assertAttached($this->repository);
223 /* -( PhabricatorPolicyInterface )----------------------------------------- */
226 public function getCapabilities() {
227 return array(
228 PhabricatorPolicyCapability::CAN_VIEW,
232 public function getPolicy($capability) {
233 // NOTE: We're passing through the repository rather than the push event
234 // mostly because we need to do policy checks in Herald before we create
235 // the event. The two approaches are equivalent in practice.
236 return $this->getRepository()->getPolicy($capability);
239 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
240 return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
243 public function describeAutomaticCapability($capability) {
244 return pht(
245 "A repository's push logs are visible to users who can see the ".
246 "repository.");