Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/differential/constants/DifferentialLintStatus.php b/src/applications/differential/constants/DifferentialLintStatus.php
index 2a519adc6c..5e16955f9b 100644
--- a/src/applications/differential/constants/DifferentialLintStatus.php
+++ b/src/applications/differential/constants/DifferentialLintStatus.php
@@ -1,12 +1,13 @@
<?php
final class DifferentialLintStatus {
const LINT_NONE = 0;
const LINT_OKAY = 1;
const LINT_WARN = 2;
const LINT_FAIL = 3;
const LINT_SKIP = 4;
const LINT_POSTPONED = 5;
+ const LINT_AUTO_SKIP = 6;
}
diff --git a/src/applications/differential/constants/DifferentialUnitStatus.php b/src/applications/differential/constants/DifferentialUnitStatus.php
index 6732d71205..9d2da07a26 100644
--- a/src/applications/differential/constants/DifferentialUnitStatus.php
+++ b/src/applications/differential/constants/DifferentialUnitStatus.php
@@ -1,12 +1,13 @@
<?php
final class DifferentialUnitStatus {
const UNIT_NONE = 0;
const UNIT_OKAY = 1;
const UNIT_WARN = 2;
const UNIT_FAIL = 3;
const UNIT_SKIP = 4;
const UNIT_POSTPONED = 5;
+ const UNIT_AUTO_SKIP = 6;
}
diff --git a/src/applications/differential/customfield/DifferentialLintField.php b/src/applications/differential/customfield/DifferentialLintField.php
index 0d5272b2f8..56b7ec3ae6 100644
--- a/src/applications/differential/customfield/DifferentialLintField.php
+++ b/src/applications/differential/customfield/DifferentialLintField.php
@@ -1,257 +1,260 @@
<?php
final class DifferentialLintField
extends DifferentialCustomField {
public function getFieldKey() {
return 'differential:lint';
}
public function getFieldName() {
return pht('Lint');
}
public function getFieldDescription() {
return pht('Shows lint results.');
}
public function shouldAppearInPropertyView() {
return true;
}
public function renderPropertyViewLabel() {
return $this->getFieldName();
}
public function getRequiredDiffPropertiesForRevisionView() {
return array(
'arc:lint',
'arc:lint-excuse',
'arc:lint-postponed',
);
}
public function renderPropertyViewValue(array $handles) {
$diff = $this->getObject()->getActiveDiff();
$path_changesets = mpull($diff->loadChangesets(), 'getID', 'getFilename');
$lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff);
$lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
$ldata = $diff->getProperty('arc:lint');
$ltail = null;
$rows = array();
$rows[] = array(
'style' => 'star',
'name' => $lstar,
'value' => $lmsg,
'show' => true,
);
$excuse = $diff->getProperty('arc:lint-excuse');
if ($excuse) {
$rows[] = array(
'style' => 'excuse',
'name' => 'Excuse',
'value' => phutil_escape_html_newlines($excuse),
'show' => true,
);
}
$show_limit = 10;
$hidden = array();
if ($ldata) {
$ldata = igroup($ldata, 'path');
foreach ($ldata as $path => $messages) {
$rows[] = array(
'style' => 'section',
'name' => $path,
'show' => $show_limit,
);
foreach ($messages as $message) {
$path = idx($message, 'path');
$line = idx($message, 'line');
$code = idx($message, 'code');
$severity = idx($message, 'severity');
$name = idx($message, 'name');
$description = idx($message, 'description');
$line_link = 'line '.intval($line);
if (isset($path_changesets[$path])) {
$href = '#C'.$path_changesets[$path].'NL'.max(1, $line);
// TODO: We are always showing the active diff
// if ($diff->getID() != $this->getDiff()->getID()) {
// $href = '/D'.$diff->getRevisionID().'?id='.$diff->getID().$href;
// }
$line_link = phutil_tag(
'a',
array(
'href' => $href,
),
$line_link);
}
if ($show_limit) {
--$show_limit;
$show = true;
} else {
$show = false;
if (empty($hidden[$severity])) {
$hidden[$severity] = 0;
}
$hidden[$severity]++;
}
$rows[] = array(
'style' => $this->getSeverityStyle($severity),
'name' => ucwords($severity),
'value' => hsprintf(
'(%s) %s at %s',
$code,
$name,
$line_link),
'show' => $show,
);
if (!empty($message['locations'])) {
$locations = array();
foreach ($message['locations'] as $location) {
$other_line = idx($location, 'line');
$locations[] =
idx($location, 'path', $path).
($other_line ? ":{$other_line}" : '');
}
$description .= "\nOther locations: ".implode(', ', $locations);
}
if (strlen($description)) {
$rows[] = array(
'style' => 'details',
'value' => phutil_escape_html_newlines($description),
'show' => false,
);
if (empty($hidden['details'])) {
$hidden['details'] = 0;
}
$hidden['details']++;
}
}
}
}
$postponed = $diff->getProperty('arc:lint-postponed');
if ($postponed) {
foreach ($postponed as $linter) {
$rows[] = array(
'style' => $this->getPostponedStyle(),
'name' => 'Postponed',
'value' => $linter,
'show' => false,
);
if (empty($hidden['postponed'])) {
$hidden['postponed'] = 0;
}
$hidden['postponed']++;
}
}
$show_string = $this->renderShowString($hidden);
$view = new DifferentialResultsTableView();
$view->setRows($rows);
$view->setShowMoreString($show_string);
return $view->render();
}
private function getSeverityStyle($severity) {
$map = array(
ArcanistLintSeverity::SEVERITY_ERROR => 'red',
ArcanistLintSeverity::SEVERITY_WARNING => 'yellow',
ArcanistLintSeverity::SEVERITY_AUTOFIX => 'yellow',
ArcanistLintSeverity::SEVERITY_ADVICE => 'yellow',
);
return idx($map, $severity);
}
private function getPostponedStyle() {
return 'blue';
}
private function renderShowString(array $hidden) {
if (!$hidden) {
return null;
}
// Reorder hidden things by severity.
$hidden = array_select_keys(
$hidden,
array(
ArcanistLintSeverity::SEVERITY_ERROR,
ArcanistLintSeverity::SEVERITY_WARNING,
ArcanistLintSeverity::SEVERITY_AUTOFIX,
ArcanistLintSeverity::SEVERITY_ADVICE,
'details',
'postponed',
)) + $hidden;
$show = array();
foreach ($hidden as $key => $value) {
switch ($key) {
case ArcanistLintSeverity::SEVERITY_ERROR:
$show[] = pht('%d Error(s)', $value);
break;
case ArcanistLintSeverity::SEVERITY_WARNING:
$show[] = pht('%d Warning(s)', $value);
break;
case ArcanistLintSeverity::SEVERITY_AUTOFIX:
$show[] = pht('%d Auto-Fix(es)', $value);
break;
case ArcanistLintSeverity::SEVERITY_ADVICE:
$show[] = pht('%d Advice(s)', $value);
break;
case 'details':
$show[] = pht('%d Detail(s)', $value);
break;
case 'postponed':
$show[] = pht('%d Postponed', $value);
break;
default:
$show[] = $value;
break;
}
}
return 'Show Full Lint Results ('.implode(', ', $show).')';
}
public function getWarningsForDetailView() {
$status = $this->getObject()->getActiveDiff()->getLintStatus();
if ($status < DifferentialLintStatus::LINT_WARN) {
return array();
}
+ if ($status == DifferentialLintStatus::LINT_AUTO_SKIP) {
+ return array();
+ }
$warnings = array();
if ($status == DifferentialLintStatus::LINT_SKIP) {
$warnings[] = pht(
'Lint was skipped when generating these changes.');
} else if ($status == DifferentialLintStatus::LINT_POSTPONED) {
$warnings[] = pht(
'Background linting has not finished executing on these changes.');
} else {
$warnings[] = pht('These changes have lint problems.');
}
return $warnings;
}
}
diff --git a/src/applications/differential/customfield/DifferentialUnitField.php b/src/applications/differential/customfield/DifferentialUnitField.php
index de76056898..6f1f782ff3 100644
--- a/src/applications/differential/customfield/DifferentialUnitField.php
+++ b/src/applications/differential/customfield/DifferentialUnitField.php
@@ -1,226 +1,228 @@
<?php
final class DifferentialUnitField
extends DifferentialCustomField {
public function getFieldKey() {
return 'differential:unit';
}
public function getFieldName() {
return pht('Unit');
}
public function getFieldDescription() {
return pht('Shows unit test results.');
}
public function shouldAppearInPropertyView() {
return true;
}
public function renderPropertyViewLabel() {
return $this->getFieldName();
}
public function getRequiredDiffPropertiesForRevisionView() {
return array(
'arc:unit',
'arc:unit-excuse',
);
}
public function renderPropertyViewValue(array $handles) {
$diff = $this->getObject()->getActiveDiff();
$ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff);
$umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
$rows = array();
$rows[] = array(
'style' => 'star',
'name' => $ustar,
'value' => $umsg,
'show' => true,
);
$excuse = $diff->getProperty('arc:unit-excuse');
if ($excuse) {
$rows[] = array(
'style' => 'excuse',
'name' => 'Excuse',
'value' => phutil_escape_html_newlines($excuse),
'show' => true,
);
}
$show_limit = 10;
$hidden = array();
$udata = $diff->getProperty('arc:unit');
if ($udata) {
$sort_map = array(
ArcanistUnitTestResult::RESULT_BROKEN => 0,
ArcanistUnitTestResult::RESULT_FAIL => 1,
ArcanistUnitTestResult::RESULT_UNSOUND => 2,
ArcanistUnitTestResult::RESULT_SKIP => 3,
ArcanistUnitTestResult::RESULT_POSTPONED => 4,
ArcanistUnitTestResult::RESULT_PASS => 5,
);
foreach ($udata as $key => $test) {
$udata[$key]['sort'] = idx($sort_map, idx($test, 'result'));
}
$udata = isort($udata, 'sort');
$engine = new PhabricatorMarkupEngine();
$engine->setViewer($this->getViewer());
$markup_objects = array();
foreach ($udata as $key => $test) {
$userdata = idx($test, 'userdata');
if ($userdata) {
if ($userdata !== false) {
$userdata = str_replace("\000", '', $userdata);
}
$markup_object = id(new PhabricatorMarkupOneOff())
->setContent($userdata)
->setPreserveLinebreaks(true);
$engine->addObject($markup_object, 'default');
$markup_objects[$key] = $markup_object;
}
}
$engine->process();
foreach ($udata as $key => $test) {
$result = idx($test, 'result');
$default_hide = false;
switch ($result) {
case ArcanistUnitTestResult::RESULT_POSTPONED:
case ArcanistUnitTestResult::RESULT_PASS:
$default_hide = true;
break;
}
if ($show_limit && !$default_hide) {
--$show_limit;
$show = true;
} else {
$show = false;
if (empty($hidden[$result])) {
$hidden[$result] = 0;
}
$hidden[$result]++;
}
$value = idx($test, 'name');
if (!empty($test['link'])) {
$value = phutil_tag(
'a',
array(
'href' => $test['link'],
'target' => '_blank',
),
$value);
}
$rows[] = array(
'style' => $this->getResultStyle($result),
'name' => ucwords($result),
'value' => $value,
'show' => $show,
);
if (isset($markup_objects[$key])) {
$rows[] = array(
'style' => 'details',
'value' => $engine->getOutput($markup_objects[$key], 'default'),
'show' => false,
);
if (empty($hidden['details'])) {
$hidden['details'] = 0;
}
$hidden['details']++;
}
}
}
$show_string = $this->renderShowString($hidden);
$view = new DifferentialResultsTableView();
$view->setRows($rows);
$view->setShowMoreString($show_string);
return $view->render();
}
private function getResultStyle($result) {
$map = array(
ArcanistUnitTestResult::RESULT_PASS => 'green',
ArcanistUnitTestResult::RESULT_FAIL => 'red',
ArcanistUnitTestResult::RESULT_SKIP => 'blue',
ArcanistUnitTestResult::RESULT_BROKEN => 'red',
ArcanistUnitTestResult::RESULT_UNSOUND => 'yellow',
ArcanistUnitTestResult::RESULT_POSTPONED => 'blue',
);
return idx($map, $result);
}
private function renderShowString(array $hidden) {
if (!$hidden) {
return null;
}
// Reorder hidden things by severity.
$hidden = array_select_keys(
$hidden,
array(
ArcanistUnitTestResult::RESULT_BROKEN,
ArcanistUnitTestResult::RESULT_FAIL,
ArcanistUnitTestResult::RESULT_UNSOUND,
ArcanistUnitTestResult::RESULT_SKIP,
ArcanistUnitTestResult::RESULT_POSTPONED,
ArcanistUnitTestResult::RESULT_PASS,
'details',
)) + $hidden;
$noun = array(
ArcanistUnitTestResult::RESULT_BROKEN => 'Broken',
ArcanistUnitTestResult::RESULT_FAIL => 'Failed',
ArcanistUnitTestResult::RESULT_UNSOUND => 'Unsound',
ArcanistUnitTestResult::RESULT_SKIP => 'Skipped',
ArcanistUnitTestResult::RESULT_POSTPONED => 'Postponed',
ArcanistUnitTestResult::RESULT_PASS => 'Passed',
);
$show = array();
foreach ($hidden as $key => $value) {
if ($key == 'details') {
$show[] = pht('%d Detail(s)', $value);
} else {
$show[] = $value.' '.idx($noun, $key);
}
}
return 'Show Full Unit Results ('.implode(', ', $show).')';
}
public function getWarningsForDetailView() {
$status = $this->getObject()->getActiveDiff()->getUnitStatus();
$warnings = array();
if ($status < DifferentialUnitStatus::UNIT_WARN) {
// Don't show any warnings.
+ } else if ($status == DifferentialUnitStatus::UNIT_AUTO_SKIP) {
+ // Don't show any warnings.
} else if ($status == DifferentialUnitStatus::UNIT_POSTPONED) {
$warnings[] = pht(
'Background tests have not finished executing on these changes.');
} else if ($status == DifferentialUnitStatus::UNIT_SKIP) {
$warnings[] = pht(
'Unit tests were skipped when generating these changes.');
} else {
$warnings[] = pht('These changes have unit test problems.');
}
return $warnings;
}
}
diff --git a/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php b/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php
index 8d18656f12..463f6c1752 100644
--- a/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php
+++ b/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php
@@ -1,422 +1,429 @@
<?php
final class DifferentialRevisionUpdateHistoryView extends AphrontView {
private $diffs = array();
private $selectedVersusDiffID;
private $selectedDiffID;
private $selectedWhitespace;
private $commitsForLinks = array();
public function setDiffs(array $diffs) {
assert_instances_of($diffs, 'DifferentialDiff');
$this->diffs = $diffs;
return $this;
}
public function setSelectedVersusDiffID($id) {
$this->selectedVersusDiffID = $id;
return $this;
}
public function setSelectedDiffID($id) {
$this->selectedDiffID = $id;
return $this;
}
public function setSelectedWhitespace($whitespace) {
$this->selectedWhitespace = $whitespace;
return $this;
}
public function setCommitsForLinks(array $commits) {
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
$this->commitsForLinks = $commits;
return $this;
}
public function render() {
$this->requireResource('differential-core-view-css');
$this->requireResource('differential-revision-history-css');
$data = array(
array(
'name' => 'Base',
'id' => null,
'desc' => 'Base',
'age' => null,
'obj' => null,
),
);
$seq = 0;
foreach ($this->diffs as $diff) {
$data[] = array(
'name' => 'Diff '.(++$seq),
'id' => $diff->getID(),
'desc' => $diff->getDescription(),
'age' => $diff->getDateCreated(),
'obj' => $diff,
);
}
$max_id = $diff->getID();
$idx = 0;
$rows = array();
$disable = false;
$radios = array();
$last_base = null;
$rowc = array();
foreach ($data as $row) {
$diff = $row['obj'];
$name = $row['name'];
$id = $row['id'];
$old_class = false;
$new_class = false;
if ($id) {
$new_checked = ($this->selectedDiffID == $id);
$new = javelin_tag(
'input',
array(
'type' => 'radio',
'name' => 'id',
'value' => $id,
'checked' => $new_checked ? 'checked' : null,
'sigil' => 'differential-new-radio',
));
if ($new_checked) {
$new_class = true;
$disable = true;
}
$new = phutil_tag(
'div',
array(
'class' => 'differential-update-history-radio',
),
$new);
} else {
$new = null;
}
if ($max_id != $id) {
$uniq = celerity_generate_unique_node_id();
$old_checked = ($this->selectedVersusDiffID == $id);
$old = phutil_tag(
'input',
array(
'type' => 'radio',
'name' => 'vs',
'value' => $id,
'id' => $uniq,
'checked' => $old_checked ? 'checked' : null,
'disabled' => $disable ? 'disabled' : null,
));
$radios[] = $uniq;
if ($old_checked) {
$old_class = true;
}
$old = phutil_tag(
'div',
array(
'class' => 'differential-update-history-radio',
),
$old);
} else {
$old = null;
}
$desc = $row['desc'];
if ($row['age']) {
$age = phabricator_datetime($row['age'], $this->getUser());
} else {
$age = null;
}
if ($diff) {
$lint = self::renderDiffLintStar($row['obj']);
$lint = phutil_tag(
'div',
array(
'class' => 'lintunit-star',
'title' => self::getDiffLintMessage($diff),
),
$lint);
$unit = self::renderDiffUnitStar($row['obj']);
$unit = phutil_tag(
'div',
array(
'class' => 'lintunit-star',
'title' => self::getDiffUnitMessage($diff),
),
$unit);
$base = $this->renderBaseRevision($diff);
} else {
$lint = null;
$unit = null;
$base = null;
}
if ($last_base !== null && $base !== $last_base) {
// TODO: Render some kind of notice about rebases.
}
$last_base = $base;
$id_link = phutil_tag(
'a',
array(
'href' => '/differential/diff/'.$id.'/',
),
$id);
$rows[] = array(
$name,
$id_link,
$base,
$desc,
$age,
$lint,
$unit,
$old,
$new,
);
$classes = array();
if ($old_class) {
$classes[] = 'differential-update-history-old-now';
}
if ($new_class) {
$classes[] = 'differential-update-history-new-now';
}
$rowc[] = nonempty(implode(' ', $classes), null);
}
Javelin::initBehavior(
'differential-diff-radios',
array(
'radios' => $radios,
));
$options = array(
DifferentialChangesetParser::WHITESPACE_IGNORE_FORCE => 'Ignore All',
DifferentialChangesetParser::WHITESPACE_IGNORE_ALL => 'Ignore Most',
DifferentialChangesetParser::WHITESPACE_IGNORE_TRAILING =>
'Ignore Trailing',
DifferentialChangesetParser::WHITESPACE_SHOW_ALL => 'Show All',
);
foreach ($options as $value => $label) {
$options[$value] = phutil_tag(
'option',
array(
'value' => $value,
'selected' => ($value == $this->selectedWhitespace)
? 'selected'
: null,
),
$label);
}
$select = phutil_tag('select', array('name' => 'whitespace'), $options);
$table = id(new AphrontTableView($rows));
$table->setHeaders(
array(
pht('Diff'),
pht('ID'),
pht('Base'),
pht('Description'),
pht('Created'),
pht('Lint'),
pht('Unit'),
'',
'',
));
$table->setColumnClasses(
array(
'pri',
'',
'',
'wide',
'date',
'center',
'center',
'center differential-update-history-old',
'center differential-update-history-new',
));
$table->setRowClasses($rowc);
$table->setDeviceVisibility(
array(
true,
true,
false,
true,
false,
false,
false,
true,
true,
));
$show_diff = phutil_tag(
'div',
array(
'class' => 'differential-update-history-footer',
),
array(
phutil_tag(
'label',
array(),
array(
pht('Whitespace Changes:'),
$select,
)),
phutil_tag(
'button',
array(),
pht('Show Diff')),
));
$content = phabricator_form(
$this->getUser(),
array(
'action' => '#toc',
),
array(
$table,
$show_diff,
));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Revision Update History'))
->setFlush(true)
->appendChild($content);
}
const STAR_NONE = 'none';
const STAR_OKAY = 'okay';
const STAR_WARN = 'warn';
const STAR_FAIL = 'fail';
const STAR_SKIP = 'skip';
public static function renderDiffLintStar(DifferentialDiff $diff) {
static $map = array(
DifferentialLintStatus::LINT_NONE => self::STAR_NONE,
DifferentialLintStatus::LINT_OKAY => self::STAR_OKAY,
DifferentialLintStatus::LINT_WARN => self::STAR_WARN,
DifferentialLintStatus::LINT_FAIL => self::STAR_FAIL,
DifferentialLintStatus::LINT_SKIP => self::STAR_SKIP,
+ DifferentialLintStatus::LINT_AUTO_SKIP => self::STAR_SKIP,
DifferentialLintStatus::LINT_POSTPONED => self::STAR_SKIP
);
$star = idx($map, $diff->getLintStatus(), self::STAR_FAIL);
return self::renderDiffStar($star);
}
public static function renderDiffUnitStar(DifferentialDiff $diff) {
static $map = array(
DifferentialUnitStatus::UNIT_NONE => self::STAR_NONE,
DifferentialUnitStatus::UNIT_OKAY => self::STAR_OKAY,
DifferentialUnitStatus::UNIT_WARN => self::STAR_WARN,
DifferentialUnitStatus::UNIT_FAIL => self::STAR_FAIL,
DifferentialUnitStatus::UNIT_SKIP => self::STAR_SKIP,
+ DifferentialUnitStatus::UNIT_AUTO_SKIP => self::STAR_SKIP,
DifferentialUnitStatus::UNIT_POSTPONED => self::STAR_SKIP,
);
$star = idx($map, $diff->getUnitStatus(), self::STAR_FAIL);
return self::renderDiffStar($star);
}
public static function getDiffLintMessage(DifferentialDiff $diff) {
switch ($diff->getLintStatus()) {
case DifferentialLintStatus::LINT_NONE:
- return 'No Linters Available';
+ return pht('No Linters Available');
case DifferentialLintStatus::LINT_OKAY:
- return 'Lint OK';
+ return pht('Lint OK');
case DifferentialLintStatus::LINT_WARN:
- return 'Lint Warnings';
+ return pht('Lint Warnings');
case DifferentialLintStatus::LINT_FAIL:
- return 'Lint Errors';
+ return pht('Lint Errors');
case DifferentialLintStatus::LINT_SKIP:
- return 'Lint Skipped';
+ return pht('Lint Skipped');
+ case DifferentialLintStatus::LINT_AUTO_SKIP:
+ return pht('Automatic diff as part of commit; lint not applicable.');
case DifferentialLintStatus::LINT_POSTPONED:
- return 'Lint Postponed';
+ return pht('Lint Postponed');
}
return '???';
}
public static function getDiffUnitMessage(DifferentialDiff $diff) {
switch ($diff->getUnitStatus()) {
case DifferentialUnitStatus::UNIT_NONE:
- return 'No Unit Test Coverage';
+ return pht('No Unit Test Coverage');
case DifferentialUnitStatus::UNIT_OKAY:
- return 'Unit Tests OK';
+ return pht('Unit Tests OK');
case DifferentialUnitStatus::UNIT_WARN:
- return 'Unit Test Warnings';
+ return pht('Unit Test Warnings');
case DifferentialUnitStatus::UNIT_FAIL:
- return 'Unit Test Errors';
+ return pht('Unit Test Errors');
case DifferentialUnitStatus::UNIT_SKIP:
- return 'Unit Tests Skipped';
+ return pht('Unit Tests Skipped');
+ case DifferentialUnitStatus::UNIT_AUTO_SKIP:
+ return pht(
+ 'Automatic diff as part of commit; unit tests not applicable.');
case DifferentialUnitStatus::UNIT_POSTPONED:
- return 'Unit Tests Postponed';
+ return pht('Unit Tests Postponed');
}
return '???';
}
private static function renderDiffStar($star) {
$class = 'diff-star-'.$star;
return phutil_tag(
'span',
array('class' => $class),
"\xE2\x98\x85");
}
private function renderBaseRevision(DifferentialDiff $diff) {
switch ($diff->getSourceControlSystem()) {
case 'git':
$base = $diff->getSourceControlBaseRevision();
if (strpos($base, '@') === false) {
$label = substr($base, 0, 7);
} else {
// The diff is from git-svn
$base = explode('@', $base);
$base = last($base);
$label = $base;
}
break;
case 'svn':
$base = $diff->getSourceControlBaseRevision();
$base = explode('@', $base);
$base = last($base);
$label = $base;
break;
default:
$label = null;
break;
}
$link = null;
if ($label) {
$commit_for_link = idx(
$this->commitsForLinks,
$diff->getSourceControlBaseRevision());
if ($commit_for_link) {
$link = phutil_tag(
'a',
array('href' => $commit_for_link->getURI()),
$label);
} else {
$link = $label;
}
}
return $link;
}
}
diff --git a/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php b/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
index a432e84853..ef25a2ef34 100644
--- a/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
+++ b/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
@@ -1,508 +1,508 @@
<?php
abstract class PhabricatorRepositoryCommitMessageParserWorker
extends PhabricatorRepositoryCommitParserWorker {
final protected function updateCommitData(DiffusionCommitRef $ref) {
$commit = $this->commit;
$author = $ref->getAuthor();
$message = $ref->getMessage();
$committer = $ref->getCommitter();
$hashes = $ref->getHashes();
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
'commitID = %d',
$commit->getID());
if (!$data) {
$data = new PhabricatorRepositoryCommitData();
}
$data->setCommitID($commit->getID());
$data->setAuthorName((string)$author);
$data->setCommitDetail('authorName', $ref->getAuthorName());
$data->setCommitDetail('authorEmail', $ref->getAuthorEmail());
$data->setCommitDetail(
'authorPHID',
$this->resolveUserPHID($commit, $author));
$data->setCommitMessage($message);
if (strlen($committer)) {
$data->setCommitDetail('committer', $committer);
$data->setCommitDetail('committerName', $ref->getCommitterName());
$data->setCommitDetail('committerEmail', $ref->getCommitterEmail());
$data->setCommitDetail(
'committerPHID',
$this->resolveUserPHID($commit, $committer));
}
$repository = $this->repository;
$author_phid = $data->getCommitDetail('authorPHID');
$committer_phid = $data->getCommitDetail('committerPHID');
$user = new PhabricatorUser();
if ($author_phid) {
$user = $user->loadOneWhere(
'phid = %s',
$author_phid);
}
$differential_app = 'PhabricatorDifferentialApplication';
$revision_id = null;
if (PhabricatorApplication::isClassInstalled($differential_app)) {
$field_values = id(new DiffusionLowLevelCommitFieldsQuery())
->setRepository($repository)
->withCommitRef($ref)
->execute();
$revision_id = idx($field_values, 'revisionID');
if (!empty($field_values['reviewedByPHIDs'])) {
$data->setCommitDetail(
'reviewerPHID',
reset($field_values['reviewedByPHIDs']));
}
$data->setCommitDetail('differential.revisionID', $revision_id);
}
if ($author_phid != $commit->getAuthorPHID()) {
$commit->setAuthorPHID($author_phid);
}
$commit->setSummary($data->getSummary());
$commit->save();
// Figure out if we're going to try to "autoclose" related objects (e.g.,
// close linked tasks and related revisions) and, if not, record why we
// aren't. Autoclose can be disabled for various reasons at the repository
// or commit levels.
$autoclose_reason = $repository->shouldSkipAutocloseCommit($commit);
$data->setCommitDetail('autocloseReason', $autoclose_reason);
$should_autoclose = $repository->shouldAutocloseCommit($commit);
// When updating related objects, we'll act under an omnipotent user to
// ensure we can see them, but take actions as either the committer or
// author (if we recognize their accounts) or the Diffusion application
// (if we do not).
$actor = PhabricatorUser::getOmnipotentUser();
$acting_as_phid = nonempty(
$committer_phid,
$author_phid,
id(new PhabricatorDiffusionApplication())->getPHID());
$conn_w = id(new DifferentialRevision())->establishConnection('w');
// NOTE: The `differential_commit` table has a unique ID on `commitPHID`,
// preventing more than one revision from being associated with a commit.
// Generally this is good and desirable, but with the advent of hash
// tracking we may end up in a situation where we match several different
// revisions. We just kind of ignore this and pick one, we might want to
// revisit this and do something differently. (If we match several revisions
// someone probably did something very silly, though.)
$revision = null;
if ($revision_id) {
$revision_query = id(new DifferentialRevisionQuery())
->withIDs(array($revision_id))
->setViewer($actor)
->needReviewerStatus(true)
->needActiveDiffs(true);
$revision = $revision_query->executeOne();
if ($revision) {
if (!$data->getCommitDetail('precommitRevisionStatus')) {
$data->setCommitDetail(
'precommitRevisionStatus',
$revision->getStatus());
}
$commit_drev = PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV;
id(new PhabricatorEdgeEditor())
->addEdge($commit->getPHID(), $commit_drev, $revision->getPHID())
->save();
queryfx(
$conn_w,
'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)',
DifferentialRevision::TABLE_COMMIT,
$revision->getID(),
$commit->getPHID());
$status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
$should_close = ($revision->getStatus() != $status_closed) &&
$should_autoclose;
if ($should_close) {
$commit_close_xaction = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
->setNewValue(DifferentialAction::ACTION_CLOSE)
->setMetadataValue('isCommitClose', true);
$commit_close_xaction->setMetadataValue(
'commitPHID',
$commit->getPHID());
$commit_close_xaction->setMetadataValue(
'committerPHID',
$committer_phid);
$commit_close_xaction->setMetadataValue(
'committerName',
$data->getCommitDetail('committer'));
$commit_close_xaction->setMetadataValue(
'authorPHID',
$author_phid);
$commit_close_xaction->setMetadataValue(
'authorName',
$data->getAuthorName());
$commit_close_xaction->setMetadataValue(
'commitHashes',
$hashes);
$diff = $this->generateFinalDiff($revision, $acting_as_phid);
$vs_diff = $this->loadChangedByCommit($revision, $diff);
$changed_uri = null;
if ($vs_diff) {
$data->setCommitDetail('vsDiff', $vs_diff->getID());
$changed_uri = PhabricatorEnv::getProductionURI(
'/D'.$revision->getID().
'?vs='.$vs_diff->getID().
'&id='.$diff->getID().
'#toc');
}
$xactions = array();
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_UPDATE)
->setIgnoreOnNoEffect(true)
->setNewValue($diff->getPHID())
->setMetadataValue('isCommitUpdate', true);
$xactions[] = $commit_close_xaction;
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_DAEMON,
array());
$editor = id(new DifferentialTransactionEditor())
->setActor($actor)
->setActingAsPHID($acting_as_phid)
->setContinueOnMissingFields(true)
->setContentSource($content_source)
->setChangedPriorToCommitURI($changed_uri)
->setIsCloseByCommit(true);
try {
$editor->applyTransactions($revision, $xactions);
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
// NOTE: We've marked transactions other than the CLOSE transaction
// as ignored when they don't have an effect, so this means that we
// lost a race to close the revision. That's perfectly fine, we can
// just continue normally.
}
}
}
}
if ($should_autoclose) {
$this->closeTasks(
$actor,
$acting_as_phid,
$repository,
$commit,
$message);
}
$data->save();
$commit->writeImportStatusFlag(
PhabricatorRepositoryCommit::IMPORTED_MESSAGE);
}
private function generateFinalDiff(
DifferentialRevision $revision,
$actor_phid) {
$viewer = PhabricatorUser::getOmnipotentUser();
$drequest = DiffusionRequest::newFromDictionary(array(
'user' => $viewer,
'repository' => $this->repository,
));
$raw_diff = DiffusionQuery::callConduitWithDiffusionRequest(
$viewer,
$drequest,
'diffusion.rawdiffquery',
array(
'commit' => $this->commit->getCommitIdentifier(),
));
// TODO: Support adds, deletes and moves under SVN.
if (strlen($raw_diff)) {
$changes = id(new ArcanistDiffParser())->parseDiff($raw_diff);
} else {
// This is an empty diff, maybe made with `git commit --allow-empty`.
// NOTE: These diffs have the same tree hash as their ancestors, so
// they may attach to revisions in an unexpected way. Just let this
// happen for now, although it might make sense to special case it
// eventually.
$changes = array();
}
$diff = DifferentialDiff::newFromRawChanges($changes)
->setRepositoryPHID($this->repository->getPHID())
->setAuthorPHID($actor_phid)
->setCreationMethod('commit')
->setSourceControlSystem($this->repository->getVersionControlSystem())
- ->setLintStatus(DifferentialLintStatus::LINT_SKIP)
- ->setUnitStatus(DifferentialUnitStatus::UNIT_SKIP)
+ ->setLintStatus(DifferentialLintStatus::LINT_AUTO_SKIP)
+ ->setUnitStatus(DifferentialUnitStatus::UNIT_AUTO_SKIP)
->setDateCreated($this->commit->getEpoch())
->setDescription(
'Commit r'.
$this->repository->getCallsign().
$this->commit->getCommitIdentifier());
// TODO: This is not correct in SVN where one repository can have multiple
// Arcanist projects.
$arcanist_project = id(new PhabricatorRepositoryArcanistProject())
->loadOneWhere('repositoryID = %d LIMIT 1', $this->repository->getID());
if ($arcanist_project) {
$diff->setArcanistProjectPHID($arcanist_project->getPHID());
}
$parents = DiffusionQuery::callConduitWithDiffusionRequest(
$viewer,
$drequest,
'diffusion.commitparentsquery',
array(
'commit' => $this->commit->getCommitIdentifier(),
));
if ($parents) {
$diff->setSourceControlBaseRevision(head($parents));
}
// TODO: Attach binary files.
return $diff->save();
}
private function loadChangedByCommit(
DifferentialRevision $revision,
DifferentialDiff $diff) {
$repository = $this->repository;
$vs_diff = id(new DifferentialDiffQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withRevisionIDs(array($revision->getID()))
->needChangesets(true)
->setLimit(1)
->executeOne();
if (!$vs_diff) {
return null;
}
if ($vs_diff->getCreationMethod() == 'commit') {
return null;
}
$vs_changesets = array();
foreach ($vs_diff->getChangesets() as $changeset) {
$path = $changeset->getAbsoluteRepositoryPath($repository, $vs_diff);
$path = ltrim($path, '/');
$vs_changesets[$path] = $changeset;
}
$changesets = array();
foreach ($diff->getChangesets() as $changeset) {
$path = $changeset->getAbsoluteRepositoryPath($repository, $diff);
$path = ltrim($path, '/');
$changesets[$path] = $changeset;
}
if (array_fill_keys(array_keys($changesets), true) !=
array_fill_keys(array_keys($vs_changesets), true)) {
return $vs_diff;
}
$file_phids = array();
foreach ($vs_changesets as $changeset) {
$metadata = $changeset->getMetadata();
$file_phid = idx($metadata, 'new:binary-phid');
if ($file_phid) {
$file_phids[$file_phid] = $file_phid;
}
}
$files = array();
if ($file_phids) {
$files = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($file_phids)
->execute();
$files = mpull($files, null, 'getPHID');
}
foreach ($changesets as $path => $changeset) {
$vs_changeset = $vs_changesets[$path];
$file_phid = idx($vs_changeset->getMetadata(), 'new:binary-phid');
if ($file_phid) {
if (!isset($files[$file_phid])) {
return $vs_diff;
}
$drequest = DiffusionRequest::newFromDictionary(array(
'user' => PhabricatorUser::getOmnipotentUser(),
'initFromConduit' => false,
'repository' => $this->repository,
'commit' => $this->commit->getCommitIdentifier(),
'path' => $path,
));
$corpus = DiffusionFileContentQuery::newFromDiffusionRequest($drequest)
->setViewer(PhabricatorUser::getOmnipotentUser())
->loadFileContent()
->getCorpus();
if ($files[$file_phid]->loadFileData() != $corpus) {
return $vs_diff;
}
} else {
$context = implode("\n", $changeset->makeChangesWithContext());
$vs_context = implode("\n", $vs_changeset->makeChangesWithContext());
// We couldn't just compare $context and $vs_context because following
// diffs will be considered different:
//
// -(empty line)
// -echo 'test';
// (empty line)
//
// (empty line)
// -echo "test";
// -(empty line)
$hunk = id(new DifferentialHunkModern())->setChanges($context);
$vs_hunk = id(new DifferentialHunkModern())->setChanges($vs_context);
if ($hunk->makeOldFile() != $vs_hunk->makeOldFile() ||
$hunk->makeNewFile() != $vs_hunk->makeNewFile()) {
return $vs_diff;
}
}
}
return null;
}
private function resolveUserPHID(
PhabricatorRepositoryCommit $commit,
$user_name) {
return id(new DiffusionResolveUserQuery())
->withCommit($commit)
->withName($user_name)
->execute();
}
private function closeTasks(
PhabricatorUser $actor,
$acting_as,
PhabricatorRepository $repository,
PhabricatorRepositoryCommit $commit,
$message) {
$maniphest = 'PhabricatorManiphestApplication';
if (!PhabricatorApplication::isClassInstalled($maniphest)) {
return;
}
$prefixes = ManiphestTaskStatus::getStatusPrefixMap();
$suffixes = ManiphestTaskStatus::getStatusSuffixMap();
$matches = id(new ManiphestCustomFieldStatusParser())
->parseCorpus($message);
$task_statuses = array();
foreach ($matches as $match) {
$prefix = phutil_utf8_strtolower($match['prefix']);
$suffix = phutil_utf8_strtolower($match['suffix']);
$status = idx($suffixes, $suffix);
if (!$status) {
$status = idx($prefixes, $prefix);
}
foreach ($match['monograms'] as $task_monogram) {
$task_id = (int)trim($task_monogram, 'tT');
$task_statuses[$task_id] = $status;
}
}
if (!$task_statuses) {
return;
}
$tasks = id(new ManiphestTaskQuery())
->setViewer($actor)
->withIDs(array_keys($task_statuses))
->execute();
foreach ($tasks as $task_id => $task) {
$xactions = array();
$edge_type = ManiphestTaskHasCommitEdgeType::EDGECONST;
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $edge_type)
->setNewValue(
array(
'+' => array(
$commit->getPHID() => $commit->getPHID(),
),
));
$status = $task_statuses[$task_id];
if ($status) {
if ($task->getStatus() != $status) {
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_STATUS)
->setNewValue($status);
$commit_name = $repository->formatCommitName(
$commit->getCommitIdentifier());
$status_message = pht(
'Closed by commit %s.',
$commit_name);
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new ManiphestTransactionComment())
->setContent($status_message));
}
}
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_DAEMON,
array());
$editor = id(new ManiphestTransactionEditor())
->setActor($actor)
->setActingAsPHID($acting_as)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setUnmentionablePHIDMap(
array($commit->getPHID() => $commit->getPHID()))
->setContentSource($content_source);
$editor->applyTransactions($task, $xactions);
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 2:25 AM (15 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140209
Default Alt Text
(45 KB)

Event Timeline