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
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';
21
const CHANGEFLAG_ADD = 1;
22
const CHANGEFLAG_DELETE = 2;
23
const CHANGEFLAG_APPEND = 4;
24
const CHANGEFLAG_REWRITE = 8;
25
const CHANGEFLAG_DANGEROUS = 16;
27
const REJECT_ACCEPT = 0;
28
const REJECT_DANGEROUS = 1;
29
const REJECT_HERALD = 2;
30
const REJECT_EXTERNAL = 3;
31
const REJECT_BROKEN = 4;
33
protected $repositoryPHID;
35
protected $pusherPHID;
36
protected $pushEventPHID;
38
protected $refNameHash;
39
protected $refNameRaw;
40
protected $refNameEncoding;
44
protected $changeFlags;
46
private $dangerousChangeDescription = self::ATTACHABLE;
47
private $pushEvent = self::ATTACHABLE;
48
private $repository = self::ATTACHABLE;
50
public static function initializeNewLog(PhabricatorUser $viewer) {
51
return id(new PhabricatorRepositoryPushLog())
52
->setPusherPHID($viewer->getPHID());
55
public static function getHeraldChangeFlagConditionOptions() {
57
PhabricatorRepositoryPushLog::CHANGEFLAG_ADD =>
58
pht('change creates ref'),
59
PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE =>
60
pht('change deletes ref'),
61
PhabricatorRepositoryPushLog::CHANGEFLAG_REWRITE =>
62
pht('change rewrites ref'),
63
PhabricatorRepositoryPushLog::CHANGEFLAG_DANGEROUS =>
64
pht('dangerous change'),
68
public function getConfiguration() {
70
self::CONFIG_AUX_PHID => true,
71
self::CONFIG_TIMESTAMPS => false,
72
self::CONFIG_BINARY => array(
75
self::CONFIG_COLUMN_SCHEMA => array(
76
'refType' => 'text12',
77
'refNameHash' => 'bytes12?',
78
'refNameRaw' => 'bytes?',
79
'refNameEncoding' => 'text16?',
80
'refOld' => 'text40?',
82
'mergeBase' => 'text40?',
83
'changeFlags' => 'uint32',
85
self::CONFIG_KEY_SCHEMA => array(
86
'key_repository' => array(
87
'columns' => array('repositoryPHID'),
90
'columns' => array('repositoryPHID', 'refNew'),
93
'columns' => array('repositoryPHID', 'refNameHash'),
96
'columns' => array('pushEventPHID'),
98
'key_pusher' => array(
99
'columns' => array('pusherPHID'),
102
) + parent::getConfiguration();
105
public function generatePHID() {
106
return PhabricatorPHID::generateNewPHID(
107
PhabricatorRepositoryPushLogPHIDType::TYPECONST);
110
public function attachPushEvent(PhabricatorRepositoryPushEvent $push_event) {
111
$this->pushEvent = $push_event;
115
public function getPushEvent() {
116
return $this->assertAttached($this->pushEvent);
119
public function getRefName() {
120
return $this->getUTF8StringFromStorage(
121
$this->getRefNameRaw(),
122
$this->getRefNameEncoding());
125
public function setRefName($ref_raw) {
126
$this->setRefNameRaw($ref_raw);
127
$this->setRefNameHash(PhabricatorHash::digestForIndex($ref_raw));
128
$this->setRefNameEncoding($this->detectEncodingForStorage($ref_raw));
133
public function getRefOldShort() {
134
if ($this->getRepository()->isSVN()) {
135
return $this->getRefOld();
137
return substr($this->getRefOld(), 0, 12);
140
public function getRefNewShort() {
141
if ($this->getRepository()->isSVN()) {
142
return $this->getRefNew();
144
return substr($this->getRefNew(), 0, 12);
147
public function hasChangeFlags($mask) {
148
return ($this->changeFlags & $mask);
151
public function attachDangerousChangeDescription($description) {
152
$this->dangerousChangeDescription = $description;
156
public function getDangerousChangeDescription() {
157
return $this->assertAttached($this->dangerousChangeDescription);
160
public function attachRepository(PhabricatorRepository $repository) {
161
// NOTE: Some gymnastics around this because of object construction order
162
// in the hook engine. Particularly, web build the logs before we build
164
$this->repository = $repository;
168
public function getRepository() {
169
if ($this->repository == self::ATTACHABLE) {
170
return $this->getPushEvent()->getRepository();
172
return $this->assertAttached($this->repository);
176
/* -( PhabricatorPolicyInterface )----------------------------------------- */
179
public function getCapabilities() {
181
PhabricatorPolicyCapability::CAN_VIEW,
185
public function getPolicy($capability) {
186
// NOTE: We're passing through the repository rather than the push event
187
// mostly because we need to do policy checks in Herald before we create
188
// the event. The two approaches are equivalent in practice.
189
return $this->getRepository()->getPolicy($capability);
192
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
193
return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
196
public function describeAutomaticCapability($capability) {
198
"A repository's push logs are visible to users who can see the ".