2011-01-24 20:01:53 +01:00
|
|
|
<?php
|
|
|
|
|
2013-07-01 21:38:42 +02:00
|
|
|
final class DifferentialDiff
|
|
|
|
extends DifferentialDAO
|
2013-12-26 19:40:52 +01:00
|
|
|
implements
|
|
|
|
PhabricatorPolicyInterface,
|
2017-01-01 17:36:38 +01:00
|
|
|
PhabricatorExtendedPolicyInterface,
|
2014-04-18 01:03:24 +02:00
|
|
|
HarbormasterBuildableInterface,
|
2015-10-15 05:01:22 +02:00
|
|
|
HarbormasterCircleCIBuildableInterface,
|
2017-02-01 00:31:15 +01:00
|
|
|
HarbormasterBuildkiteBuildableInterface,
|
2014-05-02 03:25:30 +02:00
|
|
|
PhabricatorApplicationTransactionInterface,
|
2017-10-27 20:27:53 +02:00
|
|
|
PhabricatorDestructibleInterface,
|
|
|
|
PhabricatorConduitResultInterface {
|
2011-01-24 20:01:53 +01:00
|
|
|
|
|
|
|
protected $revisionID;
|
2011-01-30 19:37:36 +01:00
|
|
|
protected $authorPHID;
|
2014-01-27 00:29:22 +01:00
|
|
|
protected $repositoryPHID;
|
When updating revisions in response to commits, reuse previously generated diffs
Summary:
Fixes T10968. In rare situations, we can generate a diff, then hit an error which causes this update to fail.
When it does, we tend to get stuck in a loop creating diffs, which can fill the database up with garbage. We saw this once in the Phacility cluster, and one instance hit it, too.
Instead: when we create a diff, keep track of which commit we generated it from. The next time through, reuse it if we already built it.
Test Plan:
- Used `bin/differential attach-commit <commit> <revision>` to hit this code.
- Simulated a filesystem write failure, saw the diff get reused.
- Also did a normal update, which worked properly.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10968
Differential Revision: https://secure.phabricator.com/D17164
2017-01-09 20:39:17 +01:00
|
|
|
protected $commitPHID;
|
2011-01-24 20:01:53 +01:00
|
|
|
|
|
|
|
protected $sourceMachine;
|
|
|
|
protected $sourcePath;
|
|
|
|
|
|
|
|
protected $sourceControlSystem;
|
|
|
|
protected $sourceControlBaseRevision;
|
|
|
|
protected $sourceControlPath;
|
|
|
|
|
|
|
|
protected $lintStatus;
|
|
|
|
protected $unitStatus;
|
|
|
|
|
|
|
|
protected $lineCount;
|
|
|
|
|
|
|
|
protected $branch;
|
2012-06-30 23:45:30 +02:00
|
|
|
protected $bookmark;
|
2011-01-24 20:01:53 +01:00
|
|
|
|
|
|
|
protected $creationMethod;
|
2011-04-06 05:49:31 +02:00
|
|
|
protected $repositoryUUID;
|
2011-01-24 20:01:53 +01:00
|
|
|
|
2011-02-05 02:53:14 +01:00
|
|
|
protected $description;
|
|
|
|
|
2014-11-19 21:16:07 +01:00
|
|
|
protected $viewPolicy;
|
|
|
|
|
2011-01-24 20:36:53 +01:00
|
|
|
private $unsavedChangesets = array();
|
2013-09-03 15:02:14 +02:00
|
|
|
private $changesets = self::ATTACHABLE;
|
2013-09-27 03:45:04 +02:00
|
|
|
private $revision = self::ATTACHABLE;
|
2014-02-27 20:06:37 +01:00
|
|
|
private $properties = array();
|
2015-06-23 16:09:23 +02:00
|
|
|
private $buildable = self::ATTACHABLE;
|
2011-01-24 20:36:53 +01:00
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
private $unitMessages = self::ATTACHABLE;
|
|
|
|
|
2015-01-13 20:47:05 +01:00
|
|
|
protected function getConfiguration() {
|
2013-11-06 22:59:06 +01:00
|
|
|
return array(
|
|
|
|
self::CONFIG_AUX_PHID => true,
|
2014-09-29 00:12:58 +02:00
|
|
|
self::CONFIG_COLUMN_SCHEMA => array(
|
|
|
|
'revisionID' => 'id?',
|
|
|
|
'authorPHID' => 'phid?',
|
|
|
|
'repositoryPHID' => 'phid?',
|
|
|
|
'sourceMachine' => 'text255?',
|
|
|
|
'sourcePath' => 'text255?',
|
|
|
|
'sourceControlSystem' => 'text64?',
|
|
|
|
'sourceControlBaseRevision' => 'text255?',
|
|
|
|
'sourceControlPath' => 'text255?',
|
|
|
|
'lintStatus' => 'uint32',
|
|
|
|
'unitStatus' => 'uint32',
|
|
|
|
'lineCount' => 'uint32',
|
|
|
|
'branch' => 'text255?',
|
|
|
|
'bookmark' => 'text255?',
|
|
|
|
'repositoryUUID' => 'text64?',
|
When updating revisions in response to commits, reuse previously generated diffs
Summary:
Fixes T10968. In rare situations, we can generate a diff, then hit an error which causes this update to fail.
When it does, we tend to get stuck in a loop creating diffs, which can fill the database up with garbage. We saw this once in the Phacility cluster, and one instance hit it, too.
Instead: when we create a diff, keep track of which commit we generated it from. The next time through, reuse it if we already built it.
Test Plan:
- Used `bin/differential attach-commit <commit> <revision>` to hit this code.
- Simulated a filesystem write failure, saw the diff get reused.
- Also did a normal update, which worked properly.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10968
Differential Revision: https://secure.phabricator.com/D17164
2017-01-09 20:39:17 +01:00
|
|
|
'commitPHID' => 'phid?',
|
2014-10-01 16:59:44 +02:00
|
|
|
|
|
|
|
// T6203/NULLABILITY
|
|
|
|
// These should be non-null; all diffs should have a creation method
|
|
|
|
// and the description should just be empty.
|
|
|
|
'creationMethod' => 'text255?',
|
|
|
|
'description' => 'text255?',
|
2014-09-29 00:12:58 +02:00
|
|
|
),
|
|
|
|
self::CONFIG_KEY_SCHEMA => array(
|
|
|
|
'revisionID' => array(
|
|
|
|
'columns' => array('revisionID'),
|
|
|
|
),
|
When updating revisions in response to commits, reuse previously generated diffs
Summary:
Fixes T10968. In rare situations, we can generate a diff, then hit an error which causes this update to fail.
When it does, we tend to get stuck in a loop creating diffs, which can fill the database up with garbage. We saw this once in the Phacility cluster, and one instance hit it, too.
Instead: when we create a diff, keep track of which commit we generated it from. The next time through, reuse it if we already built it.
Test Plan:
- Used `bin/differential attach-commit <commit> <revision>` to hit this code.
- Simulated a filesystem write failure, saw the diff get reused.
- Also did a normal update, which worked properly.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10968
Differential Revision: https://secure.phabricator.com/D17164
2017-01-09 20:39:17 +01:00
|
|
|
'key_commit' => array(
|
|
|
|
'columns' => array('commitPHID'),
|
|
|
|
),
|
2014-09-29 00:12:58 +02:00
|
|
|
),
|
2013-11-06 22:59:06 +01:00
|
|
|
) + parent::getConfiguration();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function generatePHID() {
|
|
|
|
return PhabricatorPHID::generateNewPHID(
|
2014-07-24 00:05:46 +02:00
|
|
|
DifferentialDiffPHIDType::TYPECONST);
|
2013-11-06 22:59:06 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 20:36:53 +01:00
|
|
|
public function addUnsavedChangeset(DifferentialChangeset $changeset) {
|
2011-01-25 00:52:35 +01:00
|
|
|
if ($this->changesets === null) {
|
|
|
|
$this->changesets = array();
|
|
|
|
}
|
2011-01-24 20:36:53 +01:00
|
|
|
$this->unsavedChangesets[] = $changeset;
|
2011-01-25 00:52:35 +01:00
|
|
|
$this->changesets[] = $changeset;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachChangesets(array $changesets) {
|
2012-04-04 22:13:08 +02:00
|
|
|
assert_instances_of($changesets, 'DifferentialChangeset');
|
2011-01-25 00:52:35 +01:00
|
|
|
$this->changesets = $changesets;
|
2011-01-24 20:36:53 +01:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-01-25 00:52:35 +01:00
|
|
|
public function getChangesets() {
|
2013-09-03 15:02:14 +02:00
|
|
|
return $this->assertAttached($this->changesets);
|
2011-01-25 00:52:35 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 20:01:53 +01:00
|
|
|
public function loadChangesets() {
|
|
|
|
if (!$this->getID()) {
|
|
|
|
return array();
|
|
|
|
}
|
2015-08-17 19:14:22 +02:00
|
|
|
$changesets = id(new DifferentialChangeset())->loadAllWhere(
|
2011-01-24 20:01:53 +01:00
|
|
|
'diffID = %d',
|
|
|
|
$this->getID());
|
2015-08-17 19:14:22 +02:00
|
|
|
|
|
|
|
foreach ($changesets as $changeset) {
|
|
|
|
$changeset->attachDiff($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $changesets;
|
2011-01-24 20:01:53 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 20:36:53 +01:00
|
|
|
public function save() {
|
2012-06-19 20:52:50 +02:00
|
|
|
$this->openTransaction();
|
2011-01-24 20:36:53 +01:00
|
|
|
$ret = parent::save();
|
|
|
|
foreach ($this->unsavedChangesets as $changeset) {
|
2011-01-24 21:07:34 +01:00
|
|
|
$changeset->setDiffID($this->getID());
|
|
|
|
$changeset->save();
|
2011-01-24 20:36:53 +01:00
|
|
|
}
|
2012-06-19 20:52:50 +02:00
|
|
|
$this->saveTransaction();
|
2011-01-24 20:36:53 +01:00
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
2014-11-19 21:16:07 +01:00
|
|
|
public static function initializeNewDiff(PhabricatorUser $actor) {
|
|
|
|
$app = id(new PhabricatorApplicationQuery())
|
|
|
|
->setViewer($actor)
|
|
|
|
->withClasses(array('PhabricatorDifferentialApplication'))
|
|
|
|
->executeOne();
|
|
|
|
$view_policy = $app->getPolicy(
|
|
|
|
DifferentialDefaultViewCapability::CAPABILITY);
|
|
|
|
|
|
|
|
$diff = id(new DifferentialDiff())
|
|
|
|
->setViewPolicy($view_policy);
|
|
|
|
|
|
|
|
return $diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function newFromRawChanges(
|
|
|
|
PhabricatorUser $actor,
|
|
|
|
array $changes) {
|
|
|
|
|
2012-04-04 22:13:08 +02:00
|
|
|
assert_instances_of($changes, 'ArcanistDiffChange');
|
2011-01-24 20:01:53 +01:00
|
|
|
|
2014-11-19 21:16:07 +01:00
|
|
|
$diff = self::initializeNewDiff($actor);
|
2014-12-19 23:54:15 +01:00
|
|
|
return self::buildChangesetsFromRawChanges($diff, $changes);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function newEphemeralFromRawChanges(array $changes) {
|
|
|
|
assert_instances_of($changes, 'ArcanistDiffChange');
|
|
|
|
|
|
|
|
$diff = id(new DifferentialDiff())->makeEphemeral();
|
|
|
|
return self::buildChangesetsFromRawChanges($diff, $changes);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static function buildChangesetsFromRawChanges(
|
|
|
|
DifferentialDiff $diff,
|
|
|
|
array $changes) {
|
|
|
|
|
2013-07-01 18:02:55 +02:00
|
|
|
// There may not be any changes; initialize the changesets list so that
|
|
|
|
// we don't throw later when accessing it.
|
|
|
|
$diff->attachChangesets(array());
|
|
|
|
|
2011-01-24 20:01:53 +01:00
|
|
|
$lines = 0;
|
|
|
|
foreach ($changes as $change) {
|
2012-10-19 19:29:19 +02:00
|
|
|
if ($change->getType() == ArcanistDiffChangeType::TYPE_MESSAGE) {
|
|
|
|
// If a user pastes a diff into Differential which includes a commit
|
|
|
|
// message (e.g., they ran `git show` to generate it), discard that
|
|
|
|
// change when constructing a DifferentialDiff.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-24 20:01:53 +01:00
|
|
|
$changeset = new DifferentialChangeset();
|
|
|
|
$add_lines = 0;
|
|
|
|
$del_lines = 0;
|
2012-09-21 20:57:45 +02:00
|
|
|
$first_line = PHP_INT_MAX;
|
Allow DifferentialDiff to construct proper DifferentialChangeset objects from
diffs which add empty files
Summary:
See T507 and some others. We now parse empty git diffs correctly, but the logic
to build DifferentialDiffs out of them leaves the objects with 'null' for
$changesets, when it should be array().
Further layers later throw, believing we have not loaded the changesets, when we
actually have, there just aren't any.
Test Plan: Viewed rJX05d493e17fbbb29f29e4880be6834d1d7415374e in Diffusion,
which adds an empty README file. No exception thrown.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: nh
CC: aran, nh
Differential Revision: 1038
2011-10-23 23:33:53 +02:00
|
|
|
$hunks = $change->getHunks();
|
|
|
|
if ($hunks) {
|
|
|
|
foreach ($hunks as $hunk) {
|
2018-02-10 21:04:42 +01:00
|
|
|
$dhunk = new DifferentialHunk();
|
Allow DifferentialDiff to construct proper DifferentialChangeset objects from
diffs which add empty files
Summary:
See T507 and some others. We now parse empty git diffs correctly, but the logic
to build DifferentialDiffs out of them leaves the objects with 'null' for
$changesets, when it should be array().
Further layers later throw, believing we have not loaded the changesets, when we
actually have, there just aren't any.
Test Plan: Viewed rJX05d493e17fbbb29f29e4880be6834d1d7415374e in Diffusion,
which adds an empty README file. No exception thrown.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: nh
CC: aran, nh
Differential Revision: 1038
2011-10-23 23:33:53 +02:00
|
|
|
$dhunk->setOldOffset($hunk->getOldOffset());
|
|
|
|
$dhunk->setOldLen($hunk->getOldLength());
|
|
|
|
$dhunk->setNewOffset($hunk->getNewOffset());
|
|
|
|
$dhunk->setNewLen($hunk->getNewLength());
|
|
|
|
$dhunk->setChanges($hunk->getCorpus());
|
|
|
|
$changeset->addUnsavedHunk($dhunk);
|
|
|
|
$add_lines += $hunk->getAddLines();
|
|
|
|
$del_lines += $hunk->getDelLines();
|
2012-09-21 20:57:45 +02:00
|
|
|
$added_lines = $hunk->getChangedLines('new');
|
|
|
|
if ($added_lines) {
|
|
|
|
$first_line = min($first_line, head_key($added_lines));
|
|
|
|
}
|
Allow DifferentialDiff to construct proper DifferentialChangeset objects from
diffs which add empty files
Summary:
See T507 and some others. We now parse empty git diffs correctly, but the logic
to build DifferentialDiffs out of them leaves the objects with 'null' for
$changesets, when it should be array().
Further layers later throw, believing we have not loaded the changesets, when we
actually have, there just aren't any.
Test Plan: Viewed rJX05d493e17fbbb29f29e4880be6834d1d7415374e in Diffusion,
which adds an empty README file. No exception thrown.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: nh
CC: aran, nh
Differential Revision: 1038
2011-10-23 23:33:53 +02:00
|
|
|
}
|
2012-06-27 23:45:37 +02:00
|
|
|
$lines += $add_lines + $del_lines;
|
Allow DifferentialDiff to construct proper DifferentialChangeset objects from
diffs which add empty files
Summary:
See T507 and some others. We now parse empty git diffs correctly, but the logic
to build DifferentialDiffs out of them leaves the objects with 'null' for
$changesets, when it should be array().
Further layers later throw, believing we have not loaded the changesets, when we
actually have, there just aren't any.
Test Plan: Viewed rJX05d493e17fbbb29f29e4880be6834d1d7415374e in Diffusion,
which adds an empty README file. No exception thrown.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: nh
CC: aran, nh
Differential Revision: 1038
2011-10-23 23:33:53 +02:00
|
|
|
} else {
|
|
|
|
// This happens when you add empty files.
|
|
|
|
$changeset->attachHunks(array());
|
2011-01-24 20:01:53 +01:00
|
|
|
}
|
|
|
|
|
2012-09-21 20:57:45 +02:00
|
|
|
$metadata = $change->getAllMetadata();
|
|
|
|
if ($first_line != PHP_INT_MAX) {
|
|
|
|
$metadata['line:first'] = $first_line;
|
|
|
|
}
|
|
|
|
|
2011-01-24 20:01:53 +01:00
|
|
|
$changeset->setOldFile($change->getOldPath());
|
|
|
|
$changeset->setFilename($change->getCurrentPath());
|
|
|
|
$changeset->setChangeType($change->getType());
|
|
|
|
|
|
|
|
$changeset->setFileType($change->getFileType());
|
2012-09-21 20:57:45 +02:00
|
|
|
$changeset->setMetadata($metadata);
|
2011-01-24 20:01:53 +01:00
|
|
|
$changeset->setOldProperties($change->getOldProperties());
|
|
|
|
$changeset->setNewProperties($change->getNewProperties());
|
|
|
|
$changeset->setAwayPaths($change->getAwayPaths());
|
|
|
|
$changeset->setAddLines($add_lines);
|
|
|
|
$changeset->setDelLines($del_lines);
|
|
|
|
|
2011-01-24 20:36:53 +01:00
|
|
|
$diff->addUnsavedChangeset($changeset);
|
2011-01-24 20:01:53 +01:00
|
|
|
}
|
|
|
|
$diff->setLineCount($lines);
|
|
|
|
|
2018-05-16 17:39:08 +02:00
|
|
|
$changesets = $diff->getChangesets();
|
|
|
|
|
|
|
|
id(new DifferentialChangesetEngine())
|
|
|
|
->rebuildChangesets($changesets);
|
2012-04-28 08:00:30 +02:00
|
|
|
|
2011-01-24 20:01:53 +01:00
|
|
|
return $diff;
|
|
|
|
}
|
|
|
|
|
2011-10-14 21:08:31 +02:00
|
|
|
public function getDiffDict() {
|
|
|
|
$dict = array(
|
|
|
|
'id' => $this->getID(),
|
|
|
|
'revisionID' => $this->getRevisionID(),
|
2013-01-31 05:25:07 +01:00
|
|
|
'dateCreated' => $this->getDateCreated(),
|
|
|
|
'dateModified' => $this->getDateModified(),
|
2011-10-14 21:08:31 +02:00
|
|
|
'sourceControlBaseRevision' => $this->getSourceControlBaseRevision(),
|
|
|
|
'sourceControlPath' => $this->getSourceControlPath(),
|
2012-01-09 20:42:37 +01:00
|
|
|
'sourceControlSystem' => $this->getSourceControlSystem(),
|
|
|
|
'branch' => $this->getBranch(),
|
2012-06-30 23:45:30 +02:00
|
|
|
'bookmark' => $this->getBookmark(),
|
2012-06-16 00:09:42 +02:00
|
|
|
'creationMethod' => $this->getCreationMethod(),
|
2012-06-16 01:16:03 +02:00
|
|
|
'description' => $this->getDescription(),
|
2011-10-14 21:08:31 +02:00
|
|
|
'unitStatus' => $this->getUnitStatus(),
|
|
|
|
'lintStatus' => $this->getLintStatus(),
|
|
|
|
'changes' => array(),
|
|
|
|
);
|
|
|
|
|
2013-09-17 22:55:41 +02:00
|
|
|
$dict['changes'] = $this->buildChangesList();
|
|
|
|
|
2015-10-14 19:50:53 +02:00
|
|
|
return $dict + $this->getDiffAuthorshipDict();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getDiffAuthorshipDict() {
|
2016-04-14 16:45:39 +02:00
|
|
|
$dict = array('properties' => array());
|
2015-10-14 19:50:53 +02:00
|
|
|
|
2013-09-17 22:55:41 +02:00
|
|
|
$properties = id(new DifferentialDiffProperty())->loadAllWhere(
|
|
|
|
'diffID = %d',
|
|
|
|
$this->getID());
|
|
|
|
foreach ($properties as $property) {
|
|
|
|
$dict['properties'][$property->getName()] = $property->getData();
|
|
|
|
|
|
|
|
if ($property->getName() == 'local:commits') {
|
|
|
|
foreach ($property->getData() as $commit) {
|
|
|
|
$dict['authorName'] = $commit['author'];
|
|
|
|
$dict['authorEmail'] = idx($commit, 'authorEmail');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $dict;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function buildChangesList() {
|
|
|
|
$changes = array();
|
2011-10-14 21:08:31 +02:00
|
|
|
foreach ($this->getChangesets() as $changeset) {
|
|
|
|
$hunks = array();
|
|
|
|
foreach ($changeset->getHunks() as $hunk) {
|
|
|
|
$hunks[] = array(
|
|
|
|
'oldOffset' => $hunk->getOldOffset(),
|
|
|
|
'newOffset' => $hunk->getNewOffset(),
|
|
|
|
'oldLength' => $hunk->getOldLen(),
|
|
|
|
'newLength' => $hunk->getNewLen(),
|
|
|
|
'addLines' => null,
|
|
|
|
'delLines' => null,
|
|
|
|
'isMissingOldNewline' => null,
|
|
|
|
'isMissingNewNewline' => null,
|
|
|
|
'corpus' => $hunk->getChanges(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$change = array(
|
2013-05-03 17:12:43 +02:00
|
|
|
'id' => $changeset->getID(),
|
2011-10-14 21:08:31 +02:00
|
|
|
'metadata' => $changeset->getMetadata(),
|
|
|
|
'oldPath' => $changeset->getOldFile(),
|
2012-01-17 08:05:44 +01:00
|
|
|
'currentPath' => $changeset->getFilename(),
|
2011-10-14 21:08:31 +02:00
|
|
|
'awayPaths' => $changeset->getAwayPaths(),
|
|
|
|
'oldProperties' => $changeset->getOldProperties(),
|
|
|
|
'newProperties' => $changeset->getNewProperties(),
|
|
|
|
'type' => $changeset->getChangeType(),
|
|
|
|
'fileType' => $changeset->getFileType(),
|
|
|
|
'commitHash' => null,
|
2011-12-14 20:52:28 +01:00
|
|
|
'addLines' => $changeset->getAddLines(),
|
|
|
|
'delLines' => $changeset->getDelLines(),
|
2011-10-14 21:08:31 +02:00
|
|
|
'hunks' => $hunks,
|
|
|
|
);
|
2013-09-17 22:55:41 +02:00
|
|
|
$changes[] = $change;
|
2011-10-14 21:08:31 +02:00
|
|
|
}
|
2013-09-17 22:55:41 +02:00
|
|
|
return $changes;
|
2012-11-09 22:33:58 +01:00
|
|
|
}
|
|
|
|
|
2014-11-19 21:16:07 +01:00
|
|
|
public function hasRevision() {
|
|
|
|
return $this->revision !== self::ATTACHABLE;
|
|
|
|
}
|
|
|
|
|
2013-09-27 03:45:04 +02:00
|
|
|
public function getRevision() {
|
|
|
|
return $this->assertAttached($this->revision);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachRevision(DifferentialRevision $revision = null) {
|
|
|
|
$this->revision = $revision;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-02-27 20:06:37 +01:00
|
|
|
public function attachProperty($key, $value) {
|
|
|
|
$this->properties[$key] = $value;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getProperty($key) {
|
|
|
|
return $this->assertAttachedKey($this->properties, $key);
|
|
|
|
}
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
public function hasDiffProperty($key) {
|
|
|
|
$properties = $this->getDiffProperties();
|
|
|
|
return array_key_exists($key, $properties);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachDiffProperties(array $properties) {
|
|
|
|
$this->properties = $properties;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getDiffProperties() {
|
|
|
|
return $this->assertAttached($this->properties);
|
|
|
|
}
|
|
|
|
|
2015-06-23 16:09:23 +02:00
|
|
|
public function attachBuildable(HarbormasterBuildable $buildable = null) {
|
|
|
|
$this->buildable = $buildable;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBuildable() {
|
|
|
|
return $this->assertAttached($this->buildable);
|
|
|
|
}
|
|
|
|
|
2015-08-10 23:16:36 +02:00
|
|
|
public function getBuildTargetPHIDs() {
|
|
|
|
$buildable = $this->getBuildable();
|
|
|
|
|
|
|
|
if (!$buildable) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$target_phids = array();
|
|
|
|
foreach ($buildable->getBuilds() as $build) {
|
|
|
|
foreach ($build->getBuildTargets() as $target) {
|
|
|
|
$target_phids[] = $target->getPHID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $target_phids;
|
|
|
|
}
|
2013-07-01 21:38:42 +02:00
|
|
|
|
2015-08-11 00:24:15 +02:00
|
|
|
public function loadCoverageMap(PhabricatorUser $viewer) {
|
|
|
|
$target_phids = $this->getBuildTargetPHIDs();
|
|
|
|
if (!$target_phids) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$unit = id(new HarbormasterBuildUnitMessage())->loadAllWhere(
|
|
|
|
'buildTargetPHID IN (%Ls)',
|
|
|
|
$target_phids);
|
|
|
|
|
|
|
|
$map = array();
|
|
|
|
foreach ($unit as $message) {
|
|
|
|
$coverage = $message->getProperty('coverage', array());
|
|
|
|
foreach ($coverage as $path => $coverage_data) {
|
|
|
|
$map[$path][] = $coverage_data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($map as $path => $coverage_items) {
|
|
|
|
$map[$path] = ArcanistUnitTestResult::mergeCoverage($coverage_items);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $map;
|
|
|
|
}
|
|
|
|
|
2016-01-08 13:35:17 +01:00
|
|
|
public function getURI() {
|
|
|
|
$id = $this->getID();
|
|
|
|
return "/differential/diff/{$id}/";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
public function attachUnitMessages(array $unit_messages) {
|
|
|
|
$this->unitMessages = $unit_messages;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getUnitMessages() {
|
|
|
|
return $this->assertAttached($this->unitMessages);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-01 21:38:42 +02:00
|
|
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCapabilities() {
|
|
|
|
return array(
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPolicy($capability) {
|
2014-11-19 21:16:07 +01:00
|
|
|
if ($this->hasRevision()) {
|
2017-01-01 17:36:38 +01:00
|
|
|
return PhabricatorPolicies::getMostOpenPolicy();
|
2013-09-27 03:45:04 +02:00
|
|
|
}
|
|
|
|
|
2014-11-19 21:16:07 +01:00
|
|
|
return $this->viewPolicy;
|
2013-07-01 21:38:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
2014-11-19 21:16:07 +01:00
|
|
|
if ($this->hasRevision()) {
|
2013-09-27 03:45:04 +02:00
|
|
|
return $this->getRevision()->hasAutomaticCapability($capability, $viewer);
|
|
|
|
}
|
|
|
|
|
2017-01-01 17:36:38 +01:00
|
|
|
return ($this->getAuthorPHID() == $viewer->getPHID());
|
2013-07-01 21:38:42 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 17:43:41 +02:00
|
|
|
public function describeAutomaticCapability($capability) {
|
2014-11-19 21:16:07 +01:00
|
|
|
if ($this->hasRevision()) {
|
2013-09-27 17:43:41 +02:00
|
|
|
return pht(
|
|
|
|
'This diff is attached to a revision, and inherits its policies.');
|
|
|
|
}
|
2017-01-01 17:36:38 +01:00
|
|
|
|
2014-11-19 21:16:07 +01:00
|
|
|
return pht('The author of a diff can see it.');
|
2013-09-27 17:43:41 +02:00
|
|
|
}
|
|
|
|
|
2013-12-26 19:40:52 +01:00
|
|
|
|
2017-01-01 17:36:38 +01:00
|
|
|
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
|
|
|
|
$extended = array();
|
|
|
|
|
|
|
|
switch ($capability) {
|
|
|
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
|
|
|
if ($this->hasRevision()) {
|
|
|
|
$extended[] = array(
|
|
|
|
$this->getRevision(),
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $extended;
|
|
|
|
}
|
|
|
|
|
2013-12-26 19:40:52 +01:00
|
|
|
|
|
|
|
/* -( HarbormasterBuildableInterface )------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-02-26 21:20:47 +01:00
|
|
|
public function getHarbormasterBuildableDisplayPHID() {
|
|
|
|
$container_phid = $this->getHarbormasterContainerPHID();
|
|
|
|
if ($container_phid) {
|
|
|
|
return $container_phid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->getHarbormasterBuildablePHID();
|
|
|
|
}
|
|
|
|
|
2013-12-26 19:40:52 +01:00
|
|
|
public function getHarbormasterBuildablePHID() {
|
|
|
|
return $this->getPHID();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getHarbormasterContainerPHID() {
|
|
|
|
if ($this->getRevisionID()) {
|
|
|
|
$revision = id(new DifferentialRevision())->load($this->getRevisionID());
|
|
|
|
if ($revision) {
|
|
|
|
return $revision->getPHID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2014-06-20 04:58:23 +02:00
|
|
|
public function getBuildVariables() {
|
|
|
|
$results = array();
|
|
|
|
|
|
|
|
$results['buildable.diff'] = $this->getID();
|
Add "Autoplans" to Harbormaster
Summary:
Ref T8095. Two general problems:
- I want Harbormaster to own all lint and unit test results.
- I don't want users to have to configure anything for `arc` to keep working automatically.
These are in conflict because generic lint/unit test ownership in Harbormaster requires that build targets exist which we can attach build results to. However, we can't currently create build targets on demand: Harbormaster assumes it is responsible for creating targets, then running code or making third-party service calls to actually run the builds.
I considered two broad approaches to let `arc` push results into Harbormaster without requiring administrators to configure some kind of "arc results" build plan:
# Add magic target PHIDs like `PHID-MAGIC-this-is-really-arc-unit`.
# Add new code to build real targets with real PHIDs.
(1) is probably a bit less work to get off the ground, but I think it's worse overall and very likely to create more problems in the long run. I particularly worry that it will lead to a small amount of special casing in a very large number of places, which seems more fragile.
(2) is more work upfront but I think does a better job of putting all the special casing in one place that we can, e.g., more reasonably unit test, and letting the rest of the code rarely/never care about this case since it's just dealing with normal plans/steps/targets as far as it can tell.
This diff introduces "autoplans", which are source templates for plans/steps. This let us "push" these targets into Harbormaster. Hypthetically, any process "like" arc can use autoplans to upload test/lint/etc results. In practice, probably only `arc` will ever use this, but I think it's still quite a bit cleaner than the alternative despite all the generality.
Workflow is basically:
- `arc` creates a diff.
- `arc` calls `harbormaster.queryautotargets`, passing the diff PHID and saying "I have some lint and unit results I want to stick on this thing".
- Harbormaster builds the plan, steps, and targets (if any of them don't already exist), and hands back the target PHIDs so `arc` has a completely standard-looking place to put results.
- `arc` uploads the test results to the right targets, as though Harbormaster had asked it to run unit/lint in the first place.
(This doesn't actually do any of that yet, just sets things up.)
I'll maybe doc turn that ^^^^^^ into a doc for posterity since I think it's hard to guess what an "autotarget" is, but I'm going to grab some lunch first.
Test Plan:
- Added unit tests to make sure we can build these things properly.
- Used `harbormaster.queryautotargets` to build autotargets for a bunch of diffs.
- Verified targets come up in "waiting for message" state.
- Verified plans and steps are not editable.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: hach-que, epriestley
Maniphest Tasks: T8095
Differential Revision: https://secure.phabricator.com/D13345
2015-06-21 18:04:21 +02:00
|
|
|
if ($this->revisionID) {
|
|
|
|
$revision = $this->getRevision();
|
|
|
|
$results['buildable.revision'] = $revision->getID();
|
|
|
|
$repo = $revision->getRepository();
|
|
|
|
|
|
|
|
if ($repo) {
|
|
|
|
$results['repository.callsign'] = $repo->getCallsign();
|
2015-09-25 02:29:47 +02:00
|
|
|
$results['repository.phid'] = $repo->getPHID();
|
Add "Autoplans" to Harbormaster
Summary:
Ref T8095. Two general problems:
- I want Harbormaster to own all lint and unit test results.
- I don't want users to have to configure anything for `arc` to keep working automatically.
These are in conflict because generic lint/unit test ownership in Harbormaster requires that build targets exist which we can attach build results to. However, we can't currently create build targets on demand: Harbormaster assumes it is responsible for creating targets, then running code or making third-party service calls to actually run the builds.
I considered two broad approaches to let `arc` push results into Harbormaster without requiring administrators to configure some kind of "arc results" build plan:
# Add magic target PHIDs like `PHID-MAGIC-this-is-really-arc-unit`.
# Add new code to build real targets with real PHIDs.
(1) is probably a bit less work to get off the ground, but I think it's worse overall and very likely to create more problems in the long run. I particularly worry that it will lead to a small amount of special casing in a very large number of places, which seems more fragile.
(2) is more work upfront but I think does a better job of putting all the special casing in one place that we can, e.g., more reasonably unit test, and letting the rest of the code rarely/never care about this case since it's just dealing with normal plans/steps/targets as far as it can tell.
This diff introduces "autoplans", which are source templates for plans/steps. This let us "push" these targets into Harbormaster. Hypthetically, any process "like" arc can use autoplans to upload test/lint/etc results. In practice, probably only `arc` will ever use this, but I think it's still quite a bit cleaner than the alternative despite all the generality.
Workflow is basically:
- `arc` creates a diff.
- `arc` calls `harbormaster.queryautotargets`, passing the diff PHID and saying "I have some lint and unit results I want to stick on this thing".
- Harbormaster builds the plan, steps, and targets (if any of them don't already exist), and hands back the target PHIDs so `arc` has a completely standard-looking place to put results.
- `arc` uploads the test results to the right targets, as though Harbormaster had asked it to run unit/lint in the first place.
(This doesn't actually do any of that yet, just sets things up.)
I'll maybe doc turn that ^^^^^^ into a doc for posterity since I think it's hard to guess what an "autotarget" is, but I'm going to grab some lunch first.
Test Plan:
- Added unit tests to make sure we can build these things properly.
- Used `harbormaster.queryautotargets` to build autotargets for a bunch of diffs.
- Verified targets come up in "waiting for message" state.
- Verified plans and steps are not editable.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: hach-que, epriestley
Maniphest Tasks: T8095
Differential Revision: https://secure.phabricator.com/D13345
2015-06-21 18:04:21 +02:00
|
|
|
$results['repository.vcs'] = $repo->getVersionControlSystem();
|
|
|
|
$results['repository.uri'] = $repo->getPublicCloneURI();
|
2015-10-02 01:55:01 +02:00
|
|
|
|
|
|
|
$results['repository.staging.uri'] = $repo->getStagingURI();
|
2015-10-14 00:46:30 +02:00
|
|
|
$results['repository.staging.ref'] = $this->getStagingRef();
|
Add "Autoplans" to Harbormaster
Summary:
Ref T8095. Two general problems:
- I want Harbormaster to own all lint and unit test results.
- I don't want users to have to configure anything for `arc` to keep working automatically.
These are in conflict because generic lint/unit test ownership in Harbormaster requires that build targets exist which we can attach build results to. However, we can't currently create build targets on demand: Harbormaster assumes it is responsible for creating targets, then running code or making third-party service calls to actually run the builds.
I considered two broad approaches to let `arc` push results into Harbormaster without requiring administrators to configure some kind of "arc results" build plan:
# Add magic target PHIDs like `PHID-MAGIC-this-is-really-arc-unit`.
# Add new code to build real targets with real PHIDs.
(1) is probably a bit less work to get off the ground, but I think it's worse overall and very likely to create more problems in the long run. I particularly worry that it will lead to a small amount of special casing in a very large number of places, which seems more fragile.
(2) is more work upfront but I think does a better job of putting all the special casing in one place that we can, e.g., more reasonably unit test, and letting the rest of the code rarely/never care about this case since it's just dealing with normal plans/steps/targets as far as it can tell.
This diff introduces "autoplans", which are source templates for plans/steps. This let us "push" these targets into Harbormaster. Hypthetically, any process "like" arc can use autoplans to upload test/lint/etc results. In practice, probably only `arc` will ever use this, but I think it's still quite a bit cleaner than the alternative despite all the generality.
Workflow is basically:
- `arc` creates a diff.
- `arc` calls `harbormaster.queryautotargets`, passing the diff PHID and saying "I have some lint and unit results I want to stick on this thing".
- Harbormaster builds the plan, steps, and targets (if any of them don't already exist), and hands back the target PHIDs so `arc` has a completely standard-looking place to put results.
- `arc` uploads the test results to the right targets, as though Harbormaster had asked it to run unit/lint in the first place.
(This doesn't actually do any of that yet, just sets things up.)
I'll maybe doc turn that ^^^^^^ into a doc for posterity since I think it's hard to guess what an "autotarget" is, but I'm going to grab some lunch first.
Test Plan:
- Added unit tests to make sure we can build these things properly.
- Used `harbormaster.queryautotargets` to build autotargets for a bunch of diffs.
- Verified targets come up in "waiting for message" state.
- Verified plans and steps are not editable.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: hach-que, epriestley
Maniphest Tasks: T8095
Differential Revision: https://secure.phabricator.com/D13345
2015-06-21 18:04:21 +02:00
|
|
|
}
|
2014-06-20 04:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getAvailableBuildVariables() {
|
|
|
|
return array(
|
|
|
|
'buildable.diff' =>
|
|
|
|
pht('The differential diff ID, if applicable.'),
|
|
|
|
'buildable.revision' =>
|
|
|
|
pht('The differential revision ID, if applicable.'),
|
|
|
|
'repository.callsign' =>
|
|
|
|
pht('The callsign of the repository in Phabricator.'),
|
2015-09-25 02:29:47 +02:00
|
|
|
'repository.phid' =>
|
|
|
|
pht('The PHID of the repository in Phabricator.'),
|
2014-06-20 04:58:23 +02:00
|
|
|
'repository.vcs' =>
|
|
|
|
pht('The version control system, either "svn", "hg" or "git".'),
|
|
|
|
'repository.uri' =>
|
|
|
|
pht('The URI to clone or checkout the repository from.'),
|
2015-10-02 01:55:01 +02:00
|
|
|
'repository.staging.uri' =>
|
|
|
|
pht('The URI of the staging repository.'),
|
|
|
|
'repository.staging.ref' =>
|
|
|
|
pht('The ref name for this change in the staging repository.'),
|
2014-06-20 04:58:23 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-04-03 13:39:48 +02:00
|
|
|
public function newBuildableEngine() {
|
|
|
|
return new DifferentialBuildableEngine();
|
|
|
|
}
|
|
|
|
|
2015-10-15 05:01:22 +02:00
|
|
|
|
|
|
|
/* -( HarbormasterCircleCIBuildableInterface )----------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCircleCIGitHubRepositoryURI() {
|
|
|
|
$diff_phid = $this->getPHID();
|
|
|
|
$repository_phid = $this->getRepositoryPHID();
|
|
|
|
if (!$repository_phid) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'This diff ("%s") is not associated with a repository. A diff '.
|
|
|
|
'must belong to a tracked repository to be built by CircleCI.',
|
|
|
|
$diff_phid));
|
|
|
|
}
|
|
|
|
|
|
|
|
$repository = id(new PhabricatorRepositoryQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withPHIDs(array($repository_phid))
|
|
|
|
->executeOne();
|
|
|
|
if (!$repository) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'This diff ("%s") is associated with a repository ("%s") which '.
|
|
|
|
'could not be loaded.',
|
|
|
|
$diff_phid,
|
|
|
|
$repository_phid));
|
|
|
|
}
|
|
|
|
|
|
|
|
$staging_uri = $repository->getStagingURI();
|
|
|
|
if (!$staging_uri) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'This diff ("%s") is associated with a repository ("%s") that '.
|
|
|
|
'does not have a Staging Area configured. You must configure a '.
|
|
|
|
'Staging Area to use CircleCI integration.',
|
|
|
|
$diff_phid,
|
|
|
|
$repository_phid));
|
|
|
|
}
|
|
|
|
|
|
|
|
$path = HarbormasterCircleCIBuildStepImplementation::getGitHubPath(
|
|
|
|
$staging_uri);
|
|
|
|
if (!$path) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'This diff ("%s") is associated with a repository ("%s") that '.
|
|
|
|
'does not have a Staging Area ("%s") that is hosted on GitHub. '.
|
|
|
|
'CircleCI can only build from GitHub, so the Staging Area for '.
|
|
|
|
'the repository must be hosted there.',
|
|
|
|
$diff_phid,
|
|
|
|
$repository_phid,
|
|
|
|
$staging_uri));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $staging_uri;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCircleCIBuildIdentifierType() {
|
|
|
|
return 'tag';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCircleCIBuildIdentifier() {
|
|
|
|
$ref = $this->getStagingRef();
|
|
|
|
$ref = preg_replace('(^refs/tags/)', '', $ref);
|
|
|
|
return $ref;
|
|
|
|
}
|
|
|
|
|
2017-02-01 00:31:15 +01:00
|
|
|
|
|
|
|
/* -( HarbormasterBuildkiteBuildableInterface )---------------------------- */
|
|
|
|
|
|
|
|
public function getBuildkiteBranch() {
|
|
|
|
$ref = $this->getStagingRef();
|
|
|
|
|
|
|
|
// NOTE: Circa late January 2017, Buildkite fails with the error message
|
|
|
|
// "Tags have been disabled for this project" if we pass the "refs/tags/"
|
|
|
|
// prefix via the API and the project doesn't have GitHub tag builds
|
|
|
|
// enabled, even if GitHub builds are disabled. The tag builds fine
|
|
|
|
// without this prefix.
|
|
|
|
$ref = preg_replace('(^refs/tags/)', '', $ref);
|
|
|
|
|
|
|
|
return $ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBuildkiteCommit() {
|
|
|
|
return 'HEAD';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-14 00:46:30 +02:00
|
|
|
public function getStagingRef() {
|
|
|
|
// TODO: We're just hoping to get lucky. Instead, `arc` should store
|
|
|
|
// where it sent changes and we should only provide staging details
|
|
|
|
// if we reasonably believe they are accurate.
|
|
|
|
return 'refs/tags/phabricator/diff/'.$this->getID();
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:50:58 +01:00
|
|
|
public function loadTargetBranch() {
|
|
|
|
// TODO: This is sketchy, but just eat the query cost until this can get
|
|
|
|
// cleaned up.
|
|
|
|
|
|
|
|
// For now, we're only returning a target if there's exactly one and it's
|
|
|
|
// a branch, since we don't support landing to more esoteric targets like
|
|
|
|
// tags yet.
|
|
|
|
|
|
|
|
$property = id(new DifferentialDiffProperty())->loadOneWhere(
|
|
|
|
'diffID = %d AND name = %s',
|
|
|
|
$this->getID(),
|
|
|
|
'arc:onto');
|
|
|
|
if (!$property) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$data = $property->getData();
|
|
|
|
|
|
|
|
if (!$data) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_array($data)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count($data) != 1) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$onto = head($data);
|
|
|
|
if (!is_array($onto)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$type = idx($onto, 'type');
|
|
|
|
if ($type != 'branch') {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx($onto, 'name');
|
|
|
|
}
|
|
|
|
|
2014-04-18 01:03:24 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getApplicationTransactionEditor() {
|
2014-12-01 23:46:25 +01:00
|
|
|
return new DifferentialDiffEditor();
|
2014-04-18 01:03:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationTransactionObject() {
|
2014-12-01 23:46:25 +01:00
|
|
|
return $this;
|
2014-04-18 01:03:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationTransactionTemplate() {
|
2014-12-01 23:46:25 +01:00
|
|
|
return new DifferentialDiffTransaction();
|
2014-04-18 01:03:24 +02:00
|
|
|
}
|
|
|
|
|
2014-12-04 22:58:52 +01:00
|
|
|
public function willRenderTimeline(
|
|
|
|
PhabricatorApplicationTransactionView $timeline,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
|
|
|
|
return $timeline;
|
|
|
|
}
|
|
|
|
|
2014-05-02 03:25:30 +02:00
|
|
|
|
2014-07-21 15:59:22 +02:00
|
|
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
2014-05-02 03:25:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
public function destroyObjectPermanently(
|
|
|
|
PhabricatorDestructionEngine $engine) {
|
|
|
|
|
|
|
|
$this->openTransaction();
|
|
|
|
$this->delete();
|
|
|
|
|
|
|
|
foreach ($this->loadChangesets() as $changeset) {
|
Support storage of Differential hunk data in Files
Summary:
Ref T12932. For long-lived installs, one of the largest tables tends to be the hunk data table. Although it doesn't grow tremendously fast, it's also well suited to storage in Files instead of the database (infrequent access, relatively large blobs of data, mostly one-at-a-time access), and earlier work anticipated eventually adding support for Files storage.
Make Files storage work, and provide `bin/differential migrate-hunk` to manually test/migrate hunks. This is currently the only way hunks get moved to file storage, but I expect to add a GC step which moves them to File storage after 30 days shortly.
The immediate motivation for this is to relieve storage pressure on db001/db002 so we have more headroom for deploying the Ferret engine and its larger indexes (see also T12819).
Test Plan:
- Used `bin/differential migrate-hunk` to move a hunk to and from file storage, verified it survived intact.
- Downloaded the actual stored file, sanity-checked it. Verified permissions.
- Destroyed a diff with `bin/remove destroy`, saw the hunk and file storage destroyed.
- Verified that going from file -> text destroys the old file properly with `migrate-hunk --trace ...`.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T12932
Differential Revision: https://secure.phabricator.com/D18584
2017-09-11 17:08:19 +02:00
|
|
|
$engine->destroyObject($changeset);
|
2014-05-02 03:25:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$properties = id(new DifferentialDiffProperty())->loadAllWhere(
|
|
|
|
'diffID = %d',
|
|
|
|
$this->getID());
|
|
|
|
foreach ($properties as $prop) {
|
|
|
|
$prop->delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->saveTransaction();
|
|
|
|
}
|
|
|
|
|
2017-10-27 20:27:53 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getFieldSpecificationsForConduit() {
|
|
|
|
return array(
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('revisionPHID')
|
|
|
|
->setType('phid')
|
|
|
|
->setDescription(pht('Associated revision PHID.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('authorPHID')
|
|
|
|
->setType('phid')
|
|
|
|
->setDescription(pht('Revision author PHID.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('repositoryPHID')
|
|
|
|
->setType('phid')
|
|
|
|
->setDescription(pht('Associated repository PHID.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('refs')
|
|
|
|
->setType('map<string, wild>')
|
|
|
|
->setDescription(pht('List of related VCS references.')),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFieldValuesForConduit() {
|
|
|
|
$refs = array();
|
|
|
|
|
|
|
|
$branch = $this->getBranch();
|
|
|
|
if (strlen($branch)) {
|
|
|
|
$refs[] = array(
|
|
|
|
'type' => 'branch',
|
|
|
|
'name' => $branch,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$onto = $this->loadTargetBranch();
|
|
|
|
if (strlen($onto)) {
|
|
|
|
$refs[] = array(
|
|
|
|
'type' => 'onto',
|
|
|
|
'name' => $onto,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$base = $this->getSourceControlBaseRevision();
|
|
|
|
if (strlen($base)) {
|
|
|
|
$refs[] = array(
|
|
|
|
'type' => 'base',
|
|
|
|
'identifier' => $base,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$bookmark = $this->getBookmark();
|
|
|
|
if (strlen($bookmark)) {
|
|
|
|
$refs[] = array(
|
|
|
|
'type' => 'bookmark',
|
|
|
|
'name' => $bookmark,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$revision_phid = null;
|
|
|
|
if ($this->getRevisionID()) {
|
|
|
|
$revision_phid = $this->getRevision()->getPHID();
|
|
|
|
}
|
|
|
|
|
|
|
|
return array(
|
|
|
|
'revisionPHID' => $revision_phid,
|
|
|
|
'authorPHID' => $this->getAuthorPHID(),
|
|
|
|
'repositoryPHID' => $this->getRepositoryPHID(),
|
|
|
|
'refs' => $refs,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getConduitSearchAttachments() {
|
2018-04-19 20:39:11 +02:00
|
|
|
return array(
|
|
|
|
id(new DifferentialCommitsSearchEngineAttachment())
|
|
|
|
->setAttachmentKey('commits'),
|
|
|
|
);
|
2017-10-27 20:27:53 +02:00
|
|
|
}
|
|
|
|
|
2011-01-24 20:01:53 +01:00
|
|
|
}
|