2011-01-27 23:55:52 +01:00
|
|
|
<?php
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class DifferentialRevisionViewController extends DifferentialController {
|
2011-01-27 23:55:52 +01:00
|
|
|
|
|
|
|
private $revisionID;
|
|
|
|
|
2013-09-27 03:45:04 +02:00
|
|
|
public function shouldAllowPublic() {
|
|
|
|
return true;
|
2011-10-24 21:27:16 +02:00
|
|
|
}
|
|
|
|
|
2015-10-11 17:18:42 +02:00
|
|
|
public function handleRequest(AphrontRequest $request) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
$this->revisionID = $request->getURIData('id');
|
2011-01-27 23:55:52 +01:00
|
|
|
|
2015-10-11 17:18:42 +02:00
|
|
|
$viewer_is_anonymous = !$viewer->isLoggedIn();
|
2011-01-27 23:55:52 +01:00
|
|
|
|
2013-07-16 01:01:31 +02:00
|
|
|
$revision = id(new DifferentialRevisionQuery())
|
|
|
|
->withIDs(array($this->revisionID))
|
|
|
|
->setViewer($request->getUser())
|
|
|
|
->needRelationships(true)
|
|
|
|
->needReviewerStatus(true)
|
2013-10-07 02:08:14 +02:00
|
|
|
->needReviewerAuthority(true)
|
2013-07-16 01:01:31 +02:00
|
|
|
->executeOne();
|
|
|
|
|
2011-01-27 23:55:52 +01:00
|
|
|
if (!$revision) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
2013-09-17 22:55:41 +02:00
|
|
|
$diffs = id(new DifferentialDiffQuery())
|
|
|
|
->setViewer($request->getUser())
|
|
|
|
->withRevisionIDs(array($this->revisionID))
|
|
|
|
->execute();
|
2013-09-18 20:56:48 +02:00
|
|
|
$diffs = array_reverse($diffs, $preserve_keys = true);
|
2011-01-27 23:55:52 +01:00
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
if (!$diffs) {
|
|
|
|
throw new Exception(
|
2015-05-22 09:27:56 +02:00
|
|
|
pht('This revision has no diffs. Something has gone quite wrong.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-02-27 20:06:14 +01:00
|
|
|
$revision->attachActiveDiff(last($diffs));
|
|
|
|
|
2011-02-04 00:41:58 +01:00
|
|
|
$diff_vs = $request->getInt('vs');
|
2011-04-11 21:32:08 +02:00
|
|
|
|
|
|
|
$target_id = $request->getInt('id');
|
2012-05-23 01:09:49 +02:00
|
|
|
$target = idx($diffs, $target_id, end($diffs));
|
2011-01-27 23:55:52 +01:00
|
|
|
|
2012-05-22 02:55:35 +02:00
|
|
|
$target_manual = $target;
|
|
|
|
if (!$target_id) {
|
2012-05-25 10:23:26 +02:00
|
|
|
foreach ($diffs as $diff) {
|
|
|
|
if ($diff->getCreationMethod() != 'commit') {
|
|
|
|
$target_manual = $diff;
|
|
|
|
}
|
|
|
|
}
|
2012-05-22 02:55:35 +02:00
|
|
|
}
|
|
|
|
|
2011-02-04 00:41:58 +01:00
|
|
|
if (empty($diffs[$diff_vs])) {
|
|
|
|
$diff_vs = null;
|
|
|
|
}
|
|
|
|
|
2014-04-14 21:07:32 +02:00
|
|
|
$repository = null;
|
|
|
|
$repository_phid = $target->getRepositoryPHID();
|
|
|
|
if ($repository_phid) {
|
|
|
|
if ($repository_phid == $revision->getRepositoryPHID()) {
|
|
|
|
$repository = $revision->getRepository();
|
|
|
|
} else {
|
|
|
|
$repository = id(new PhabricatorRepositoryQuery())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setViewer($viewer)
|
2014-04-14 21:07:32 +02:00
|
|
|
->withPHIDs(array($repository_phid))
|
|
|
|
->executeOne();
|
|
|
|
}
|
|
|
|
}
|
2012-06-28 19:12:20 +02:00
|
|
|
|
|
|
|
list($changesets, $vs_map, $vs_changesets, $rendering_references) =
|
|
|
|
$this->loadChangesetsAndVsMap(
|
|
|
|
$target,
|
|
|
|
idx($diffs, $diff_vs),
|
|
|
|
$repository);
|
|
|
|
|
|
|
|
if ($request->getExists('download')) {
|
2013-01-22 03:41:38 +01:00
|
|
|
return $this->buildRawDiffResponse(
|
2013-12-30 20:27:02 +01:00
|
|
|
$revision,
|
2013-01-22 03:41:38 +01:00
|
|
|
$changesets,
|
|
|
|
$vs_changesets,
|
|
|
|
$vs_map,
|
|
|
|
$repository);
|
2012-06-28 19:12:20 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 00:32:23 +02:00
|
|
|
$map = $vs_map;
|
|
|
|
if (!$map) {
|
|
|
|
$map = array_fill_keys(array_keys($changesets), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
$old_ids = array();
|
|
|
|
$new_ids = array();
|
|
|
|
foreach ($map as $id => $vs) {
|
|
|
|
if ($vs <= 0) {
|
|
|
|
$old_ids[] = $id;
|
|
|
|
$new_ids[] = $id;
|
|
|
|
} else {
|
|
|
|
$new_ids[] = $id;
|
|
|
|
$new_ids[] = $vs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
$this->loadDiffProperties($diffs);
|
|
|
|
$props = $target_manual->getDiffProperties();
|
2011-08-14 20:29:56 +02:00
|
|
|
|
2011-01-27 23:55:52 +01:00
|
|
|
$object_phids = array_merge(
|
|
|
|
$revision->getReviewers(),
|
|
|
|
$revision->getCCPHIDs(),
|
2011-04-08 06:59:42 +02:00
|
|
|
$revision->loadCommitPHIDs(),
|
2011-01-27 23:55:52 +01:00
|
|
|
array(
|
2011-01-30 19:37:36 +01:00
|
|
|
$revision->getAuthorPHID(),
|
2015-10-11 17:18:42 +02:00
|
|
|
$viewer->getPHID(),
|
2014-03-09 21:44:54 +01:00
|
|
|
));
|
2011-06-01 20:19:55 +02:00
|
|
|
|
2011-02-17 23:32:01 +01:00
|
|
|
foreach ($revision->getAttached() as $type => $phids) {
|
|
|
|
foreach ($phids as $phid => $info) {
|
|
|
|
$object_phids[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
2011-08-14 21:33:54 +02:00
|
|
|
|
2014-07-02 13:58:51 +02:00
|
|
|
$field_list = PhabricatorCustomField::getObjectFields(
|
|
|
|
$revision,
|
|
|
|
PhabricatorCustomField::ROLE_VIEW);
|
|
|
|
|
2015-10-11 17:18:42 +02:00
|
|
|
$field_list->setViewer($viewer);
|
2014-07-02 13:58:51 +02:00
|
|
|
$field_list->readFieldsFromStorage($revision);
|
|
|
|
|
|
|
|
$warning_handle_map = array();
|
|
|
|
foreach ($field_list->getFields() as $key => $field) {
|
|
|
|
$req = $field->getRequiredHandlePHIDsForRevisionHeaderWarnings();
|
|
|
|
foreach ($req as $phid) {
|
|
|
|
$warning_handle_map[$key][] = $phid;
|
|
|
|
$object_phids[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-05 04:02:56 +02:00
|
|
|
$handles = $this->loadViewerHandles($object_phids);
|
2011-01-27 23:55:52 +01:00
|
|
|
|
2011-02-06 01:43:28 +01:00
|
|
|
$request_uri = $request->getRequestURI();
|
|
|
|
|
|
|
|
$limit = 100;
|
|
|
|
$large = $request->getStr('large');
|
|
|
|
if (count($changesets) > $limit && !$large) {
|
2013-01-28 22:32:56 +01:00
|
|
|
$count = count($changesets);
|
2015-03-01 23:45:56 +01:00
|
|
|
$warning = new PHUIInfoView();
|
2015-05-22 09:27:56 +02:00
|
|
|
$warning->setTitle(pht('Very Large Diff'));
|
2015-03-01 23:45:56 +01:00
|
|
|
$warning->setSeverity(PHUIInfoView::SEVERITY_WARNING);
|
2013-02-07 01:53:49 +01:00
|
|
|
$warning->appendChild(hsprintf(
|
|
|
|
'%s <strong>%s</strong>',
|
2013-01-28 22:32:56 +01:00
|
|
|
pht(
|
2014-11-03 18:31:23 +01:00
|
|
|
'This diff is very large and affects %s files. '.
|
|
|
|
'You may load each file individually or ',
|
2013-02-07 01:53:49 +01:00
|
|
|
new PhutilNumber($count)),
|
|
|
|
phutil_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
2014-11-03 18:31:23 +01:00
|
|
|
'class' => 'button grey',
|
2013-02-07 01:53:49 +01:00
|
|
|
'href' => $request_uri
|
|
|
|
->alter('large', 'true')
|
|
|
|
->setFragment('toc'),
|
|
|
|
),
|
|
|
|
pht('Show All Files Inline'))));
|
2011-02-06 01:43:28 +01:00
|
|
|
$warning = $warning->render();
|
|
|
|
|
2015-04-22 00:32:23 +02:00
|
|
|
$old = array_select_keys($changesets, $old_ids);
|
|
|
|
$new = array_select_keys($changesets, $new_ids);
|
2015-04-22 00:31:18 +02:00
|
|
|
|
|
|
|
$query = id(new DifferentialInlineCommentQuery())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setViewer($viewer)
|
Allow inline comments to be individually hidden
Summary:
Ref T7447. Implements per-viewer comment hiding. Once a comment is obsolete or uninteresting, you can hide it completely.
This is sticky per-user.
My hope is that this will strike a better balance between concerns than some of the other approaches (conservative porting, summarization, hide-all).
Specifically, this adds a new action here:
{F435621}
Clicking it completely collapses the comment into a small icon on the previous line, and saves the comment state as hidden for you:
{F435626}
You can click the icon to reveal all hidden comments below the line.
Test Plan:
- Hid comments.
- Showed comments.
- Created, edited, deleted and submitted comments.
- Used Diffusion comments (hiding is not implemented there yet, but I'd plan to bring it there eventually if it works out in Differential).
Reviewers: btrahan, chad
Reviewed By: btrahan
Subscribers: jparise, yelirekim, epriestley
Maniphest Tasks: T7447
Differential Revision: https://secure.phabricator.com/D13009
2015-05-27 19:28:38 +02:00
|
|
|
->needHidden(true)
|
2015-04-22 00:31:18 +02:00
|
|
|
->withRevisionPHIDs(array($revision->getPHID()));
|
|
|
|
$inlines = $query->execute();
|
2015-05-04 20:52:21 +02:00
|
|
|
$inlines = $query->adjustInlinesForChangesets(
|
|
|
|
$inlines,
|
|
|
|
$old,
|
|
|
|
$new,
|
|
|
|
$revision);
|
2012-08-07 05:42:43 +02:00
|
|
|
|
2011-04-15 23:25:23 +02:00
|
|
|
$visible_changesets = array();
|
2015-04-22 00:31:18 +02:00
|
|
|
foreach ($inlines as $inline) {
|
2012-05-29 20:23:23 +02:00
|
|
|
$changeset_id = $inline->getChangesetID();
|
|
|
|
if (isset($changesets[$changeset_id])) {
|
|
|
|
$visible_changesets[$changeset_id] = $changesets[$changeset_id];
|
|
|
|
}
|
|
|
|
}
|
2011-02-06 01:43:28 +01:00
|
|
|
} else {
|
|
|
|
$warning = null;
|
|
|
|
$visible_changesets = $changesets;
|
|
|
|
}
|
|
|
|
|
2014-04-02 22:18:11 +02:00
|
|
|
$commit_hashes = mpull($diffs, 'getSourceControlBaseRevision');
|
|
|
|
$local_commits = idx($props, 'local:commits', array());
|
|
|
|
foreach ($local_commits as $local_commit) {
|
|
|
|
$commit_hashes[] = idx($local_commit, 'tree');
|
|
|
|
$commit_hashes[] = idx($local_commit, 'local');
|
|
|
|
}
|
|
|
|
$commit_hashes = array_unique(array_filter($commit_hashes));
|
2014-04-11 03:09:54 +02:00
|
|
|
if ($commit_hashes) {
|
|
|
|
$commits_for_links = id(new DiffusionCommitQuery())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setViewer($viewer)
|
2014-04-11 03:09:54 +02:00
|
|
|
->withIdentifiers($commit_hashes)
|
|
|
|
->execute();
|
|
|
|
$commits_for_links = mpull(
|
|
|
|
$commits_for_links,
|
|
|
|
null,
|
|
|
|
'getCommitIdentifier');
|
|
|
|
} else {
|
2014-04-11 13:18:12 +02:00
|
|
|
$commits_for_links = array();
|
2014-04-11 03:09:54 +02:00
|
|
|
}
|
2014-02-27 20:06:37 +01:00
|
|
|
|
2013-07-13 19:33:32 +02:00
|
|
|
$revision_detail = id(new DifferentialRevisionDetailView())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setUser($viewer)
|
2013-07-13 19:33:32 +02:00
|
|
|
->setRevision($revision)
|
|
|
|
->setDiff(end($diffs))
|
2014-02-27 20:06:14 +01:00
|
|
|
->setCustomFields($field_list)
|
2013-07-13 19:33:32 +02:00
|
|
|
->setURI($request->getRequestURI());
|
2011-01-27 23:55:52 +01:00
|
|
|
|
2011-08-14 22:55:30 +02:00
|
|
|
$actions = $this->getRevisionActions($revision);
|
|
|
|
|
2011-04-28 06:16:35 +02:00
|
|
|
$whitespace = $request->getStr(
|
|
|
|
'whitespace',
|
2015-02-10 08:34:43 +01:00
|
|
|
DifferentialChangesetParser::WHITESPACE_IGNORE_MOST);
|
2011-04-28 06:16:35 +02:00
|
|
|
|
2015-05-18 15:29:47 +02:00
|
|
|
$repository = $revision->getRepository();
|
|
|
|
if ($repository) {
|
2015-05-21 17:25:34 +02:00
|
|
|
$symbol_indexes = $this->buildSymbolIndexes(
|
2015-05-18 15:29:47 +02:00
|
|
|
$repository,
|
2012-01-05 23:41:11 +01:00
|
|
|
$visible_changesets);
|
|
|
|
} else {
|
|
|
|
$symbol_indexes = array();
|
|
|
|
}
|
2011-01-27 23:55:52 +01:00
|
|
|
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
$revision_detail->setActions($actions);
|
2015-10-11 17:18:42 +02:00
|
|
|
$revision_detail->setUser($viewer);
|
2011-04-13 03:17:43 +02:00
|
|
|
|
2014-02-22 00:10:58 +01:00
|
|
|
$revision_detail_box = $revision_detail->render();
|
|
|
|
|
2014-07-02 13:58:51 +02:00
|
|
|
$revision_warnings = $this->buildRevisionWarnings(
|
|
|
|
$revision,
|
|
|
|
$field_list,
|
|
|
|
$warning_handle_map,
|
|
|
|
$handles);
|
2014-02-22 00:10:58 +01:00
|
|
|
if ($revision_warnings) {
|
2015-03-01 23:45:56 +01:00
|
|
|
$revision_warnings = id(new PHUIInfoView())
|
|
|
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
2014-07-02 13:58:51 +02:00
|
|
|
->setErrors($revision_warnings);
|
2015-03-07 02:03:18 +01:00
|
|
|
$revision_detail_box->setInfoView($revision_warnings);
|
2014-02-22 00:10:58 +01:00
|
|
|
}
|
|
|
|
|
2015-06-23 16:09:23 +02:00
|
|
|
$detail_diffs = array_select_keys(
|
|
|
|
$diffs,
|
|
|
|
array($diff_vs, $target->getID()));
|
|
|
|
$detail_diffs = mpull($detail_diffs, null, 'getPHID');
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
$this->loadHarbormasterData($detail_diffs);
|
2015-06-23 16:09:23 +02:00
|
|
|
|
2015-06-16 17:53:40 +02:00
|
|
|
$diff_detail_box = $this->buildDiffDetailView(
|
2015-06-23 16:09:23 +02:00
|
|
|
$detail_diffs,
|
2015-06-16 17:53:40 +02:00
|
|
|
$revision,
|
|
|
|
$field_list);
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
$unit_box = $this->buildUnitMessagesView(
|
|
|
|
$target,
|
|
|
|
$revision);
|
|
|
|
|
2014-02-12 23:05:40 +01:00
|
|
|
$comment_view = $this->buildTransactions(
|
|
|
|
$revision,
|
2014-02-14 01:03:23 +01:00
|
|
|
$diff_vs ? $diffs[$diff_vs] : $target,
|
2015-04-22 00:32:23 +02:00
|
|
|
$target,
|
|
|
|
$old_ids,
|
|
|
|
$new_ids);
|
2011-01-30 19:37:36 +01:00
|
|
|
|
2014-05-05 19:55:58 +02:00
|
|
|
if (!$viewer_is_anonymous) {
|
|
|
|
$comment_view->setQuoteRef('D'.$revision->getID());
|
|
|
|
$comment_view->setQuoteTargetID('comment-content');
|
|
|
|
}
|
|
|
|
|
2014-02-14 00:06:38 +01:00
|
|
|
$wrap_id = celerity_generate_unique_node_id();
|
|
|
|
$comment_view = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'id' => $wrap_id,
|
|
|
|
),
|
|
|
|
$comment_view);
|
|
|
|
|
2011-04-28 01:19:31 +02:00
|
|
|
$changeset_view = new DifferentialChangesetListView();
|
2012-05-01 21:09:50 +02:00
|
|
|
$changeset_view->setChangesets($changesets);
|
|
|
|
$changeset_view->setVisibleChangesets($visible_changesets);
|
Add inline comments to Diffusion/Audit
Summary:
- Add inline comments to Audits, like Differential.
- Creates new storage for the comments in the Audits database.
- Creates a new PhabricatorAuditInlineComment class, similar to DifferentialInlineComment.
- Defines an Interface which Differential and Audit comments conform to.
- Makes consumers of DifferentialInlineComments consume objects which implement that interface instead.
- Adds save
NOTE: Some features are still missing! Wanted to cut this off before it got crazy:
- Inline comments aren't shown in the main comment list.
- Inline comments aren't shown in the emails.
- Inline comments aren't previewed.
I'll followup with those but this was getting pretty big.
@vrana, does the SQL change look correct?
Test Plan:
- Created, edited, deleted, replied to, reloaded and saved inline comments in Diffusion, on the left and right side of diffs.
- Created, edited, deleted, replied to, reloaded and saved inline comments in Differentila, on the left and right side of primary and diff-versus-diff diffs.
Reviewers: btrahan, vrana
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T904
Differential Revision: https://secure.phabricator.com/D1898
2012-03-14 20:56:01 +01:00
|
|
|
|
|
|
|
if (!$viewer_is_anonymous) {
|
|
|
|
$changeset_view->setInlineCommentControllerURI(
|
|
|
|
'/differential/comment/inline/edit/'.$revision->getID().'/');
|
|
|
|
}
|
|
|
|
|
2012-03-20 03:57:41 +01:00
|
|
|
$changeset_view->setStandaloneURI('/differential/changeset/');
|
|
|
|
$changeset_view->setRawFileURIs(
|
|
|
|
'/differential/changeset/?view=old',
|
|
|
|
'/differential/changeset/?view=new');
|
|
|
|
|
2015-10-11 17:18:42 +02:00
|
|
|
$changeset_view->setUser($viewer);
|
2012-01-05 23:41:11 +01:00
|
|
|
$changeset_view->setDiff($target);
|
Move "Rendering References" to the DifferentialChangesetParser level
Summary:
Separates changeset IDs from rendering. Now each changeset has a "rendering
reference" which is basically a description of what the ajax endpoint should
render. For Differential, it's in the form "id/vs". For Diffusion,
"branch/path;commit".
I believe this fixes pretty much all of the bugs related to "show more" breaking
in various obscure ways, although I never got a great repro for T153.
Test Plan:
Clicked "show more" in diffusion change and commit views and differential diff,
diff-of-diff, standalone-diff, standalone-diff-of-diff views. Verified refs and
'whitespace' were always sent correctly.
Made inline comments on diffs and diffs-of-diffs. Used "Reply".
Reviewed By: tuomaspelkonen
Reviewers: tuomaspelkonen, jungejason, aran
CC: aran, tuomaspelkonen, epriestley
Differential Revision: 274
2011-05-12 06:46:29 +02:00
|
|
|
$changeset_view->setRenderingReferences($rendering_references);
|
Resolve great internal confusion about left vs right inline comments
Summary:
This code was just all kinds of wrong, but got all the common cases anyone cares
about correct.
- In edit-inline-comments.js, if isOnRight() is true, use data.right, not
data.left (derp).
- Set data.left correctly, not to the same value as data.right (derp derp).
- Set "isNewFile" based on $is_new, not $on_right (derp derp derp).
Test Plan:
- Added JS debugging code to print "OLD" vs "NEW" and "LEFT" vs "RIGHT".
Clicked the left and right sides of diff-vs-base and diff-vs-diff diffs,
verified output was accurate in all cases.
- Added comments to the left-display-side of a diff-of-diffs, saved them, they
showed up where I put them.
Reviewers: btrahan, vrana
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T543
Differential Revision: https://secure.phabricator.com/D1567
2012-02-04 00:26:47 +01:00
|
|
|
$changeset_view->setVsMap($vs_map);
|
2011-04-28 06:16:35 +02:00
|
|
|
$changeset_view->setWhitespace($whitespace);
|
2012-01-05 23:41:11 +01:00
|
|
|
if ($repository) {
|
2012-06-12 01:22:08 +02:00
|
|
|
$changeset_view->setRepository($repository);
|
2012-01-05 23:41:11 +01:00
|
|
|
}
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
$changeset_view->setSymbolIndexes($symbol_indexes);
|
2015-05-22 09:27:56 +02:00
|
|
|
$changeset_view->setTitle(pht('Diff %s', $target->getID()));
|
2011-04-28 01:19:31 +02:00
|
|
|
|
2014-04-02 22:18:11 +02:00
|
|
|
$diff_history = id(new DifferentialRevisionUpdateHistoryView())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setUser($viewer)
|
2014-04-02 22:18:11 +02:00
|
|
|
->setDiffs($diffs)
|
|
|
|
->setSelectedVersusDiffID($diff_vs)
|
|
|
|
->setSelectedDiffID($target->getID())
|
|
|
|
->setSelectedWhitespace($whitespace)
|
|
|
|
->setCommitsForLinks($commits_for_links);
|
2011-01-30 19:37:36 +01:00
|
|
|
|
2014-04-02 22:18:11 +02:00
|
|
|
$local_view = id(new DifferentialLocalCommitsView())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setUser($viewer)
|
2014-04-02 22:18:11 +02:00
|
|
|
->setLocalCommits(idx($props, 'local:commits'))
|
|
|
|
->setCommitsForLinks($commits_for_links);
|
2011-08-30 20:34:07 +02:00
|
|
|
|
2012-04-10 22:34:31 +02:00
|
|
|
if ($repository) {
|
|
|
|
$other_revisions = $this->loadOtherRevisions(
|
|
|
|
$changesets,
|
|
|
|
$target,
|
|
|
|
$repository);
|
|
|
|
} else {
|
|
|
|
$other_revisions = array();
|
|
|
|
}
|
2012-03-30 19:13:08 +02:00
|
|
|
|
|
|
|
$other_view = null;
|
|
|
|
if ($other_revisions) {
|
|
|
|
$other_view = $this->renderOtherRevisions($other_revisions);
|
|
|
|
}
|
|
|
|
|
2015-08-15 20:43:12 +02:00
|
|
|
$toc_view = $this->buildTableOfContents(
|
|
|
|
$changesets,
|
|
|
|
$visible_changesets,
|
2015-10-11 17:18:42 +02:00
|
|
|
$target->loadCoverageMap($viewer));
|
2011-01-30 19:37:36 +01:00
|
|
|
|
2012-05-10 00:56:37 +02:00
|
|
|
$comment_form = null;
|
2011-10-24 21:27:16 +02:00
|
|
|
if (!$viewer_is_anonymous) {
|
|
|
|
$draft = id(new PhabricatorDraft())->loadOneWhere(
|
|
|
|
'authorPHID = %s AND draftKey = %s',
|
2015-10-11 17:18:42 +02:00
|
|
|
$viewer->getPHID(),
|
2011-10-24 21:27:16 +02:00
|
|
|
'differential-comment-'.$revision->getID());
|
2012-09-20 23:11:11 +02:00
|
|
|
|
|
|
|
$reviewers = array();
|
|
|
|
$ccs = array();
|
2011-10-24 21:27:16 +02:00
|
|
|
if ($draft) {
|
2012-09-20 23:11:11 +02:00
|
|
|
$reviewers = idx($draft->getMetadata(), 'reviewers', array());
|
|
|
|
$ccs = idx($draft->getMetadata(), 'ccs', array());
|
|
|
|
if ($reviewers || $ccs) {
|
|
|
|
$handles = $this->loadViewerHandles(array_merge($reviewers, $ccs));
|
|
|
|
$reviewers = array_select_keys($handles, $reviewers);
|
|
|
|
$ccs = array_select_keys($handles, $ccs);
|
|
|
|
}
|
2011-10-24 21:27:16 +02:00
|
|
|
}
|
2011-02-06 01:57:21 +01:00
|
|
|
|
2011-10-24 21:27:16 +02:00
|
|
|
$comment_form = new DifferentialAddCommentView();
|
|
|
|
$comment_form->setRevision($revision);
|
2014-02-27 20:06:14 +01:00
|
|
|
|
2014-03-09 21:18:17 +01:00
|
|
|
$review_warnings = array();
|
|
|
|
foreach ($field_list->getFields() as $field) {
|
|
|
|
$review_warnings[] = $field->getWarningsForDetailView();
|
|
|
|
}
|
|
|
|
$review_warnings = array_mergev($review_warnings);
|
|
|
|
|
|
|
|
if ($review_warnings) {
|
2015-03-01 23:45:56 +01:00
|
|
|
$review_warnings_panel = id(new PHUIInfoView())
|
|
|
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
2014-03-09 21:18:17 +01:00
|
|
|
->setErrors($review_warnings);
|
2015-03-07 02:03:18 +01:00
|
|
|
$comment_form->setInfoView($review_warnings_panel);
|
2014-03-09 21:18:17 +01:00
|
|
|
}
|
|
|
|
|
2011-10-24 21:27:16 +02:00
|
|
|
$comment_form->setActions($this->getRevisionCommentActions($revision));
|
2014-02-27 20:06:55 +01:00
|
|
|
$action_uri = $this->getApplicationURI(
|
|
|
|
'comment/save/'.$revision->getID().'/');
|
2014-02-25 00:57:26 +01:00
|
|
|
|
|
|
|
$comment_form->setActionURI($action_uri);
|
2015-10-11 17:18:42 +02:00
|
|
|
$comment_form->setUser($viewer);
|
2011-10-24 21:27:16 +02:00
|
|
|
$comment_form->setDraft($draft);
|
2012-09-20 23:11:11 +02:00
|
|
|
$comment_form->setReviewers(mpull($reviewers, 'getFullName', 'getPHID'));
|
|
|
|
$comment_form->setCCs(mpull($ccs, 'getFullName', 'getPHID'));
|
2013-10-20 01:43:33 +02:00
|
|
|
|
|
|
|
// TODO: This just makes the "Z" key work. Generalize this and remove
|
|
|
|
// it at some point.
|
|
|
|
$comment_form = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'differential-add-comment-panel',
|
|
|
|
),
|
|
|
|
$comment_form);
|
2011-10-24 21:27:16 +02:00
|
|
|
}
|
Differential Updates View
Summary:
This adds a new view to differential called Updates.
The high-level goal of Updates is to enabled differential to be
effectively used without email notifications. I've tried doing things
like automatically deleting differential emails where I'm in the 'to'
line since they show up on the main diffential page but then there's
always the chance an important diff flies by without me seeing it. Also,
sometimes someone comments on a diff post-commit but differential
doesn't surface those diffs.
I re-created a test db on my devserver using mysqldump to get data on
revs > 230000 so I would have some test data. We need to add a simple
viewtime table but I didn't want to do that in production. Here's the
table:
CREATE TABLE differential_viewtime (
viewerPHID varchar(64) not null,
objectPHID varchar(64) not null,
viewTime int unsigned not null,
PRIMARY KEY (viewerPHID, objectPHID)
);
Issues:
-Once we turn this on, all diffs will be 'unviewed'. What do you think
about a 'Clear All' button or something?
-Maybe we should add a pager
This feature would be insanely useful, let me know what you think.
Test Plan:
Loaded Updates in my sandbox
http://phabricator.dev1577.snc6.facebook.com/differential/filter/updates/
Clicked a diff, then went back, made sure diff disappeared from Updates
list
Reviewed By: tuomaspelkonen
Reviewers: epriestley, jungejason, tuomaspelkonen
Commenters: epriestley
CC: epriestley, elynde, tuomaspelkonen
Differential Revision: 169
2011-04-27 10:27:06 +02:00
|
|
|
|
2011-07-08 22:00:30 +02:00
|
|
|
$pane_id = celerity_generate_unique_node_id();
|
|
|
|
Javelin::initBehavior(
|
|
|
|
'differential-keyboard-navigation',
|
|
|
|
array(
|
|
|
|
'haunt' => $pane_id,
|
|
|
|
));
|
2012-04-17 03:53:38 +02:00
|
|
|
Javelin::initBehavior('differential-user-select');
|
2011-07-08 22:00:30 +02:00
|
|
|
|
2011-10-24 21:27:16 +02:00
|
|
|
$page_pane = id(new DifferentialPrimaryPaneView())
|
|
|
|
->setID($pane_id)
|
2015-03-09 01:35:51 +01:00
|
|
|
->appendChild($comment_view);
|
|
|
|
|
|
|
|
$signatures = DifferentialRequiredSignaturesField::loadForRevision(
|
|
|
|
$revision);
|
|
|
|
$missing_signatures = false;
|
|
|
|
foreach ($signatures as $phid => $signed) {
|
|
|
|
if (!$signed) {
|
|
|
|
$missing_signatures = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($missing_signatures) {
|
|
|
|
$signature_message = id(new PHUIInfoView())
|
|
|
|
->setErrors(
|
|
|
|
array(
|
|
|
|
array(
|
|
|
|
phutil_tag('strong', array(), pht('Content Hidden:')),
|
|
|
|
' ',
|
|
|
|
pht(
|
|
|
|
'The content of this revision is hidden until the author has '.
|
|
|
|
'signed all of the required legal agreements.'),
|
|
|
|
),
|
|
|
|
));
|
|
|
|
$page_pane->appendChild($signature_message);
|
|
|
|
} else {
|
|
|
|
$page_pane->appendChild(
|
|
|
|
array(
|
|
|
|
$diff_history,
|
|
|
|
$warning,
|
|
|
|
$local_view,
|
|
|
|
$toc_view,
|
|
|
|
$other_view,
|
|
|
|
$changeset_view,
|
|
|
|
));
|
|
|
|
}
|
2014-05-05 19:55:58 +02:00
|
|
|
|
2015-03-09 01:35:51 +01:00
|
|
|
if ($comment_form) {
|
2013-10-20 01:43:33 +02:00
|
|
|
$page_pane->appendChild($comment_form);
|
2013-09-27 03:45:04 +02:00
|
|
|
} else {
|
|
|
|
// TODO: For now, just use this to get "Login to Comment".
|
|
|
|
$page_pane->appendChild(
|
|
|
|
id(new PhabricatorApplicationTransactionCommentView())
|
2015-10-11 17:18:42 +02:00
|
|
|
->setUser($viewer)
|
2013-09-27 03:45:04 +02:00
|
|
|
->setRequestURI($request->getRequestURI()));
|
2011-10-24 21:27:16 +02:00
|
|
|
}
|
2012-06-09 03:45:26 +02:00
|
|
|
|
upgrade diffusion to use modern header UI and fix a few quirks
Summary:
upgrades are CrumbsView, HeaderView, PropertyListView, and ActionListView. I had to modify CrumbsView stuff a bit to handle the "advanced" diffusion crumbs.
Quirks fixed include making file tree view show up in diffusion, the page not have extra space when the file tree is hidden, links no longer breaking once you visit files (since without the change the files always got "/" appended and thus 404'd), and a differential quirk where it read "next step:" and that colon is a no no,
Test Plan: played around in diffusion and differential
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, Korvin, chad
Maniphest Tasks: T2048, T2178
Differential Revision: https://secure.phabricator.com/D4169
2012-12-13 02:50:42 +01:00
|
|
|
$object_id = 'D'.$revision->getID();
|
|
|
|
|
2015-10-14 00:46:12 +02:00
|
|
|
$operations_box = $this->buildOperationsBox($revision);
|
|
|
|
|
2013-02-05 02:00:27 +01:00
|
|
|
$content = array(
|
2015-10-14 00:46:12 +02:00
|
|
|
$operations_box,
|
2014-02-22 00:10:58 +01:00
|
|
|
$revision_detail_box,
|
2015-06-16 17:53:40 +02:00
|
|
|
$diff_detail_box,
|
2016-02-29 18:53:46 +01:00
|
|
|
$unit_box,
|
2013-02-05 02:00:27 +01:00
|
|
|
$page_pane,
|
|
|
|
);
|
2012-12-07 22:37:45 +01:00
|
|
|
|
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
2013-12-19 02:47:34 +01:00
|
|
|
$crumbs->addTextCrumb($object_id, '/'.$object_id);
|
2013-02-05 02:00:27 +01:00
|
|
|
|
2015-10-11 17:18:42 +02:00
|
|
|
$prefs = $viewer->loadPreferences();
|
2013-02-05 02:00:27 +01:00
|
|
|
|
|
|
|
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
|
|
|
|
if ($prefs->getPreference($pref_filetree)) {
|
|
|
|
$collapsed = $prefs->getPreference(
|
|
|
|
PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED,
|
|
|
|
false);
|
|
|
|
|
|
|
|
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
|
|
|
|
->setTitle('D'.$revision->getID())
|
|
|
|
->setBaseURI(new PhutilURI('/D'.$revision->getID()))
|
|
|
|
->setCollapsed((bool)$collapsed)
|
|
|
|
->build($changesets);
|
|
|
|
} else {
|
2016-03-10 22:18:58 +01:00
|
|
|
$nav = null;
|
2013-02-05 02:00:27 +01:00
|
|
|
}
|
2012-12-07 22:37:45 +01:00
|
|
|
|
2016-03-10 22:18:58 +01:00
|
|
|
$page = $this->newPage()
|
|
|
|
->setTitle($object_id.' '.$revision->getTitle())
|
|
|
|
->setCrumbs($crumbs)
|
|
|
|
->setPageObjectPHIDs(array($revision->getPHID()))
|
|
|
|
->appendChild($content);
|
|
|
|
|
|
|
|
if ($nav) {
|
|
|
|
$page->setNavigation($nav);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $page;
|
2011-01-27 23:55:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function getRevisionActions(DifferentialRevision $revision) {
|
2014-02-21 20:55:35 +01:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
2011-01-27 23:55:52 +01:00
|
|
|
$revision_id = $revision->getID();
|
|
|
|
$revision_phid = $revision->getPHID();
|
|
|
|
|
2013-09-27 03:45:04 +02:00
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
2014-02-21 20:55:35 +01:00
|
|
|
$viewer,
|
2013-09-27 03:45:04 +02:00
|
|
|
$revision,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
2014-02-27 20:06:14 +01:00
|
|
|
$actions = array();
|
2014-02-21 20:55:35 +01:00
|
|
|
|
2014-02-27 20:06:14 +01:00
|
|
|
$actions[] = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2014-02-27 20:06:14 +01:00
|
|
|
->setHref("/differential/revision/edit/{$revision_id}/")
|
|
|
|
->setName(pht('Edit Revision'))
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit);
|
2013-09-27 03:45:04 +02:00
|
|
|
|
2015-03-23 18:44:33 +01:00
|
|
|
$actions[] = id(new PhabricatorActionView())
|
|
|
|
->setIcon('fa-upload')
|
|
|
|
->setHref("/differential/revision/update/{$revision_id}/")
|
|
|
|
->setName(pht('Update Diff'))
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit);
|
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
$this->requireResource('phabricator-object-selector-css');
|
|
|
|
$this->requireResource('javelin-behavior-phabricator-object-selector');
|
2011-10-24 21:27:16 +02:00
|
|
|
|
2014-02-27 20:06:14 +01:00
|
|
|
$actions[] = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-link')
|
2014-02-27 20:06:14 +01:00
|
|
|
->setName(pht('Edit Dependencies'))
|
|
|
|
->setHref("/search/attach/{$revision_phid}/DREV/dependencies/")
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setDisabled(!$can_edit);
|
2011-10-24 21:27:16 +02:00
|
|
|
|
2014-07-23 02:03:09 +02:00
|
|
|
$maniphest = 'PhabricatorManiphestApplication';
|
2013-09-27 03:45:04 +02:00
|
|
|
if (PhabricatorApplication::isClassInstalled($maniphest)) {
|
2014-02-27 20:06:14 +01:00
|
|
|
$actions[] = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-anchor')
|
2014-02-27 20:06:14 +01:00
|
|
|
->setName(pht('Edit Maniphest Tasks'))
|
|
|
|
->setHref("/search/attach/{$revision_phid}/TASK/")
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setDisabled(!$can_edit);
|
2011-04-13 21:12:02 +02:00
|
|
|
}
|
2011-02-17 23:32:01 +01:00
|
|
|
|
2012-06-28 19:12:20 +02:00
|
|
|
$request_uri = $this->getRequest()->getRequestURI();
|
2014-02-27 20:06:14 +01:00
|
|
|
$actions[] = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-download')
|
2014-02-27 20:06:14 +01:00
|
|
|
->setName(pht('Download Raw Diff'))
|
|
|
|
->setHref($request_uri->alter('download', 'true'));
|
2012-06-28 19:12:20 +02:00
|
|
|
|
2014-02-27 20:06:14 +01:00
|
|
|
return $actions;
|
2011-01-27 23:55:52 +01:00
|
|
|
}
|
|
|
|
|
2011-01-30 20:02:22 +01:00
|
|
|
private function getRevisionCommentActions(DifferentialRevision $revision) {
|
|
|
|
$actions = array(
|
|
|
|
DifferentialAction::ACTION_COMMENT => true,
|
|
|
|
);
|
|
|
|
|
2011-10-25 23:03:34 +02:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
$viewer_phid = $viewer->getPHID();
|
2011-01-30 20:02:22 +01:00
|
|
|
$viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID());
|
2011-04-11 19:38:10 +02:00
|
|
|
$viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
|
2012-04-17 23:59:31 +02:00
|
|
|
$status = $revision->getStatus();
|
2011-01-30 20:02:22 +01:00
|
|
|
|
2013-10-07 02:09:02 +02:00
|
|
|
$viewer_has_accepted = false;
|
|
|
|
$viewer_has_rejected = false;
|
|
|
|
$status_accepted = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
|
|
|
$status_rejected = DifferentialReviewerStatus::STATUS_REJECTED;
|
|
|
|
foreach ($revision->getReviewerStatus() as $reviewer) {
|
|
|
|
if ($reviewer->getReviewerPHID() == $viewer_phid) {
|
|
|
|
if ($reviewer->getStatus() == $status_accepted) {
|
|
|
|
$viewer_has_accepted = true;
|
|
|
|
}
|
|
|
|
if ($reviewer->getStatus() == $status_rejected) {
|
|
|
|
$viewer_has_rejected = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-03 09:38:49 +02:00
|
|
|
$allow_self_accept = PhabricatorEnv::getEnvConfig(
|
2013-01-19 21:11:11 +01:00
|
|
|
'differential.allow-self-accept');
|
2014-06-03 01:58:48 +02:00
|
|
|
$always_allow_abandon = PhabricatorEnv::getEnvConfig(
|
|
|
|
'differential.always-allow-abandon');
|
2012-08-28 23:17:23 +02:00
|
|
|
$always_allow_close = PhabricatorEnv::getEnvConfig(
|
2013-01-19 21:11:11 +01:00
|
|
|
'differential.always-allow-close');
|
2013-01-19 18:10:15 +01:00
|
|
|
$allow_reopen = PhabricatorEnv::getEnvConfig(
|
2013-01-19 21:11:11 +01:00
|
|
|
'differential.allow-reopen');
|
2012-07-03 09:38:49 +02:00
|
|
|
|
2011-01-30 20:02:22 +01:00
|
|
|
if ($viewer_is_owner) {
|
2012-04-17 23:59:31 +02:00
|
|
|
switch ($status) {
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
|
2012-07-03 09:38:49 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept;
|
2011-01-30 20:02:22 +01:00
|
|
|
$actions[DifferentialAction::ACTION_ABANDON] = true;
|
2011-04-14 01:10:54 +02:00
|
|
|
$actions[DifferentialAction::ACTION_RETHINK] = true;
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
|
2014-03-05 19:47:47 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED:
|
2012-07-03 09:38:49 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept;
|
2011-04-14 01:10:54 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ABANDON] = true;
|
|
|
|
$actions[DifferentialAction::ACTION_REQUEST] = true;
|
|
|
|
break;
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::ACCEPTED:
|
2011-01-30 20:02:22 +01:00
|
|
|
$actions[DifferentialAction::ACTION_ABANDON] = true;
|
|
|
|
$actions[DifferentialAction::ACTION_REQUEST] = true;
|
2011-04-14 01:10:54 +02:00
|
|
|
$actions[DifferentialAction::ACTION_RETHINK] = true;
|
2012-04-24 02:40:57 +02:00
|
|
|
$actions[DifferentialAction::ACTION_CLOSE] = true;
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
2012-04-24 02:40:57 +02:00
|
|
|
case ArcanistDifferentialRevisionStatus::CLOSED:
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::ABANDONED:
|
2011-01-30 20:02:22 +01:00
|
|
|
$actions[DifferentialAction::ACTION_RECLAIM] = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2012-04-17 23:59:31 +02:00
|
|
|
switch ($status) {
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
|
2014-06-03 01:58:48 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon;
|
2011-01-30 20:02:22 +01:00
|
|
|
$actions[DifferentialAction::ACTION_ACCEPT] = true;
|
|
|
|
$actions[DifferentialAction::ACTION_REJECT] = true;
|
2011-04-11 19:38:10 +02:00
|
|
|
$actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
|
2014-03-05 19:47:47 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED:
|
2014-06-03 01:58:48 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon;
|
2011-01-30 20:02:22 +01:00
|
|
|
$actions[DifferentialAction::ACTION_ACCEPT] = true;
|
2013-10-07 02:09:02 +02:00
|
|
|
$actions[DifferentialAction::ACTION_REJECT] = !$viewer_has_rejected;
|
2011-04-11 19:38:10 +02:00
|
|
|
$actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::ACCEPTED:
|
2014-06-03 01:58:48 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon;
|
2013-10-07 02:09:02 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ACCEPT] = !$viewer_has_accepted;
|
2011-01-30 20:02:22 +01:00
|
|
|
$actions[DifferentialAction::ACTION_REJECT] = true;
|
2013-10-07 02:09:02 +02:00
|
|
|
$actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
2012-04-24 02:40:57 +02:00
|
|
|
case ArcanistDifferentialRevisionStatus::CLOSED:
|
2012-01-10 20:39:11 +01:00
|
|
|
case ArcanistDifferentialRevisionStatus::ABANDONED:
|
2011-01-30 20:02:22 +01:00
|
|
|
break;
|
|
|
|
}
|
2012-04-24 02:40:57 +02:00
|
|
|
if ($status != ArcanistDifferentialRevisionStatus::CLOSED) {
|
2012-04-17 23:59:31 +02:00
|
|
|
$actions[DifferentialAction::ACTION_CLAIM] = true;
|
2012-08-28 23:17:23 +02:00
|
|
|
$actions[DifferentialAction::ACTION_CLOSE] = $always_allow_close;
|
2012-04-17 23:59:31 +02:00
|
|
|
}
|
2011-01-30 20:02:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$actions[DifferentialAction::ACTION_ADDREVIEWERS] = true;
|
2011-06-24 21:21:48 +02:00
|
|
|
$actions[DifferentialAction::ACTION_ADDCCS] = true;
|
2013-01-19 18:10:15 +01:00
|
|
|
$actions[DifferentialAction::ACTION_REOPEN] = $allow_reopen &&
|
|
|
|
($status == ArcanistDifferentialRevisionStatus::CLOSED);
|
2011-01-30 20:02:22 +01:00
|
|
|
|
2011-10-27 21:32:02 +02:00
|
|
|
$actions = array_keys(array_filter($actions));
|
|
|
|
$actions_dict = array();
|
|
|
|
foreach ($actions as $action) {
|
|
|
|
$actions_dict[$action] = DifferentialAction::getActionVerb($action);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $actions_dict;
|
2011-01-30 20:02:22 +01:00
|
|
|
}
|
|
|
|
|
2012-04-04 22:13:08 +02:00
|
|
|
private function loadChangesetsAndVsMap(
|
2012-05-23 01:09:49 +02:00
|
|
|
DifferentialDiff $target,
|
|
|
|
DifferentialDiff $diff_vs = null,
|
|
|
|
PhabricatorRepository $repository = null) {
|
2012-04-04 22:13:08 +02:00
|
|
|
|
2014-06-11 18:05:09 +02:00
|
|
|
$load_diffs = array($target);
|
2011-02-04 00:41:58 +01:00
|
|
|
if ($diff_vs) {
|
2014-06-11 18:05:09 +02:00
|
|
|
$load_diffs[] = $diff_vs;
|
2011-02-04 00:41:58 +01:00
|
|
|
}
|
|
|
|
|
2014-06-11 18:05:09 +02:00
|
|
|
$raw_changesets = id(new DifferentialChangesetQuery())
|
|
|
|
->setViewer($this->getRequest()->getUser())
|
|
|
|
->withDiffs($load_diffs)
|
|
|
|
->execute();
|
2011-02-04 00:41:58 +01:00
|
|
|
$changeset_groups = mgroup($raw_changesets, 'getDiffID');
|
|
|
|
|
|
|
|
$changesets = idx($changeset_groups, $target->getID(), array());
|
|
|
|
$changesets = mpull($changesets, null, 'getID');
|
|
|
|
|
2012-06-28 19:12:20 +02:00
|
|
|
$refs = array();
|
|
|
|
$vs_map = array();
|
|
|
|
$vs_changesets = array();
|
2011-02-04 00:41:58 +01:00
|
|
|
if ($diff_vs) {
|
2012-06-28 19:12:20 +02:00
|
|
|
$vs_id = $diff_vs->getID();
|
|
|
|
$vs_changesets_path_map = array();
|
2012-05-23 01:09:49 +02:00
|
|
|
foreach (idx($changeset_groups, $vs_id, array()) as $changeset) {
|
|
|
|
$path = $changeset->getAbsoluteRepositoryPath($repository, $diff_vs);
|
2012-06-28 19:12:20 +02:00
|
|
|
$vs_changesets_path_map[$path] = $changeset;
|
|
|
|
$vs_changesets[$changeset->getID()] = $changeset;
|
2012-05-23 01:09:49 +02:00
|
|
|
}
|
2011-02-04 00:41:58 +01:00
|
|
|
foreach ($changesets as $key => $changeset) {
|
2012-06-28 19:12:20 +02:00
|
|
|
$path = $changeset->getAbsoluteRepositoryPath($repository, $target);
|
|
|
|
if (isset($vs_changesets_path_map[$path])) {
|
|
|
|
$vs_map[$changeset->getID()] =
|
|
|
|
$vs_changesets_path_map[$path]->getID();
|
Move "Rendering References" to the DifferentialChangesetParser level
Summary:
Separates changeset IDs from rendering. Now each changeset has a "rendering
reference" which is basically a description of what the ajax endpoint should
render. For Differential, it's in the form "id/vs". For Diffusion,
"branch/path;commit".
I believe this fixes pretty much all of the bugs related to "show more" breaking
in various obscure ways, although I never got a great repro for T153.
Test Plan:
Clicked "show more" in diffusion change and commit views and differential diff,
diff-of-diff, standalone-diff, standalone-diff-of-diff views. Verified refs and
'whitespace' were always sent correctly.
Made inline comments on diffs and diffs-of-diffs. Used "Reply".
Reviewed By: tuomaspelkonen
Reviewers: tuomaspelkonen, jungejason, aran
CC: aran, tuomaspelkonen, epriestley
Differential Revision: 274
2011-05-12 06:46:29 +02:00
|
|
|
$refs[$changeset->getID()] =
|
2012-06-28 19:12:20 +02:00
|
|
|
$changeset->getID().'/'.$vs_changesets_path_map[$path]->getID();
|
|
|
|
unset($vs_changesets_path_map[$path]);
|
Move "Rendering References" to the DifferentialChangesetParser level
Summary:
Separates changeset IDs from rendering. Now each changeset has a "rendering
reference" which is basically a description of what the ajax endpoint should
render. For Differential, it's in the form "id/vs". For Diffusion,
"branch/path;commit".
I believe this fixes pretty much all of the bugs related to "show more" breaking
in various obscure ways, although I never got a great repro for T153.
Test Plan:
Clicked "show more" in diffusion change and commit views and differential diff,
diff-of-diff, standalone-diff, standalone-diff-of-diff views. Verified refs and
'whitespace' were always sent correctly.
Made inline comments on diffs and diffs-of-diffs. Used "Reply".
Reviewed By: tuomaspelkonen
Reviewers: tuomaspelkonen, jungejason, aran
CC: aran, tuomaspelkonen, epriestley
Differential Revision: 274
2011-05-12 06:46:29 +02:00
|
|
|
} else {
|
|
|
|
$refs[$changeset->getID()] = $changeset->getID();
|
2011-02-04 00:41:58 +01:00
|
|
|
}
|
|
|
|
}
|
2012-06-28 19:12:20 +02:00
|
|
|
foreach ($vs_changesets_path_map as $path => $changeset) {
|
2011-02-04 00:41:58 +01:00
|
|
|
$changesets[$changeset->getID()] = $changeset;
|
2012-06-28 19:12:20 +02:00
|
|
|
$vs_map[$changeset->getID()] = -1;
|
|
|
|
$refs[$changeset->getID()] = $changeset->getID().'/-1';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
foreach ($changesets as $changeset) {
|
|
|
|
$refs[$changeset->getID()] = $changeset->getID();
|
2011-02-04 00:41:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$changesets = msort($changesets, 'getSortKey');
|
|
|
|
|
2012-06-28 19:12:20 +02:00
|
|
|
return array($changesets, $vs_map, $vs_changesets, $refs);
|
2011-02-04 00:41:58 +01:00
|
|
|
}
|
|
|
|
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
private function buildSymbolIndexes(
|
2015-05-18 15:29:47 +02:00
|
|
|
PhabricatorRepository $repository,
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
array $visible_changesets) {
|
2012-04-04 22:13:08 +02:00
|
|
|
assert_instances_of($visible_changesets, 'DifferentialChangeset');
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
|
|
|
|
$engine = PhabricatorSyntaxHighlighter::newEngine();
|
|
|
|
|
2015-05-18 15:29:47 +02:00
|
|
|
$langs = $repository->getSymbolLanguages();
|
|
|
|
$langs = nonempty($langs, array());
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
|
2015-05-21 17:25:34 +02:00
|
|
|
$sources = $repository->getSymbolSources();
|
|
|
|
$sources = nonempty($sources, array());
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
|
2012-01-05 23:41:11 +01:00
|
|
|
$symbol_indexes = array();
|
|
|
|
|
2015-05-21 17:25:34 +02:00
|
|
|
if ($langs && $sources) {
|
|
|
|
$have_symbols = id(new DiffusionSymbolQuery())
|
|
|
|
->existsSymbolsInRepository($repository->getPHID());
|
|
|
|
if (!$have_symbols) {
|
|
|
|
return $symbol_indexes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-18 15:29:47 +02:00
|
|
|
$repository_phids = array_merge(
|
|
|
|
array($repository->getPHID()),
|
2015-05-21 17:25:34 +02:00
|
|
|
$sources);
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
|
|
|
|
$indexed_langs = array_fill_keys($langs, true);
|
|
|
|
foreach ($visible_changesets as $key => $changeset) {
|
2012-01-17 08:05:44 +01:00
|
|
|
$lang = $engine->getLanguageFromFilename($changeset->getFilename());
|
2015-05-18 15:29:47 +02:00
|
|
|
if (empty($indexed_langs) || isset($indexed_langs[$lang])) {
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
$symbol_indexes[$key] = array(
|
2015-05-18 15:29:47 +02:00
|
|
|
'lang' => $lang,
|
|
|
|
'repositories' => $repository_phids,
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-21 17:25:34 +02:00
|
|
|
return $symbol_indexes;
|
Tie all the pieces for symbol cross-references together
Summary:
This makes symbol cross-references work in Differential. You need to do a little
legwork but I'll document that once the change has baked for a little while.
Basically:
- Projects are annotated with indexed languages, and "shared library" projects
(for example, symbols in Phabricator should be searched for in Arcanist and
libphutil).
- When we render a changeset, we check if its language is an indexed one. If
it is, we invoke the decorator Javascript.
- The Javascript takes you to a lookup page, which either gives you a list of
matching symbols (if several match) or redirects you instantly to the
definition.
Test Plan: Clicked class and function symbols in a diff, got jumped into
sensible sorts of places in Diffusion.
Reviewers: jungejason, nh, tuomaspelkonen, aran
Reviewed By: jungejason
CC: aran, jungejason
Differential Revision: 980
2011-10-03 01:02:56 +02:00
|
|
|
}
|
|
|
|
|
2012-04-10 08:42:12 +02:00
|
|
|
private function loadOtherRevisions(
|
|
|
|
array $changesets,
|
|
|
|
DifferentialDiff $target,
|
|
|
|
PhabricatorRepository $repository) {
|
|
|
|
assert_instances_of($changesets, 'DifferentialChangeset');
|
|
|
|
|
2012-03-30 19:13:08 +02:00
|
|
|
$paths = array();
|
|
|
|
foreach ($changesets as $changeset) {
|
|
|
|
$paths[] = $changeset->getAbsoluteRepositoryPath(
|
2012-04-10 08:42:12 +02:00
|
|
|
$repository,
|
|
|
|
$target);
|
2012-03-30 19:13:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!$paths) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$path_map = id(new DiffusionPathIDQuery($paths))->loadPathIDs();
|
|
|
|
|
|
|
|
if (!$path_map) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
2015-03-25 18:21:56 +01:00
|
|
|
$recent = (PhabricatorTime::getNow() - phutil_units('30 days in seconds'));
|
|
|
|
|
2012-03-30 19:13:08 +02:00
|
|
|
$query = id(new DifferentialRevisionQuery())
|
2013-07-01 21:38:27 +02:00
|
|
|
->setViewer($this->getRequest()->getUser())
|
2012-03-30 19:13:08 +02:00
|
|
|
->withStatus(DifferentialRevisionQuery::STATUS_OPEN)
|
2015-03-25 18:21:56 +01:00
|
|
|
->withUpdatedEpochBetween($recent, null)
|
2015-04-12 05:16:52 +02:00
|
|
|
->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED)
|
2012-03-30 19:13:08 +02:00
|
|
|
->setLimit(10)
|
2014-02-19 02:57:45 +01:00
|
|
|
->needFlags(true)
|
|
|
|
->needDrafts(true)
|
2012-03-30 19:13:08 +02:00
|
|
|
->needRelationships(true);
|
|
|
|
|
|
|
|
foreach ($path_map as $path => $path_id) {
|
|
|
|
$query->withPath($repository->getID(), $path_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
$results = $query->execute();
|
|
|
|
|
|
|
|
// Strip out *this* revision.
|
|
|
|
foreach ($results as $key => $result) {
|
|
|
|
if ($result->getID() == $this->revisionID) {
|
|
|
|
unset($results[$key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function renderOtherRevisions(array $revisions) {
|
2012-04-04 22:13:08 +02:00
|
|
|
assert_instances_of($revisions, 'DifferentialRevision');
|
2015-03-25 18:21:56 +01:00
|
|
|
$viewer = $this->getViewer();
|
2012-04-04 22:13:08 +02:00
|
|
|
|
2015-03-25 18:21:56 +01:00
|
|
|
$header = id(new PHUIHeaderView())
|
2015-05-20 08:14:22 +02:00
|
|
|
->setHeader(pht('Recent Similar Open Revisions'));
|
2013-03-01 02:15:09 +01:00
|
|
|
|
2012-03-30 19:13:08 +02:00
|
|
|
$view = id(new DifferentialRevisionListView())
|
2015-03-25 18:21:56 +01:00
|
|
|
->setHeader($header)
|
2012-03-30 19:13:08 +02:00
|
|
|
->setRevisions($revisions)
|
2015-03-25 18:21:56 +01:00
|
|
|
->setUser($viewer);
|
2012-03-30 19:13:08 +02:00
|
|
|
|
|
|
|
$phids = $view->getRequiredHandlePHIDs();
|
2012-09-05 04:02:56 +02:00
|
|
|
$handles = $this->loadViewerHandles($phids);
|
2012-03-30 19:13:08 +02:00
|
|
|
$view->setHandles($handles);
|
|
|
|
|
2015-02-19 17:11:17 +01:00
|
|
|
return $view;
|
2012-03-30 19:13:08 +02:00
|
|
|
}
|
2011-08-14 22:55:30 +02:00
|
|
|
|
2012-06-28 19:12:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Note this code is somewhat similar to the buildPatch method in
|
|
|
|
* @{class:DifferentialReviewRequestMail}.
|
|
|
|
*
|
|
|
|
* @return @{class:AphrontRedirectResponse}
|
|
|
|
*/
|
|
|
|
private function buildRawDiffResponse(
|
2013-12-30 20:27:02 +01:00
|
|
|
DifferentialRevision $revision,
|
2012-06-28 19:12:20 +02:00
|
|
|
array $changesets,
|
|
|
|
array $vs_changesets,
|
|
|
|
array $vs_map,
|
|
|
|
PhabricatorRepository $repository = null) {
|
|
|
|
|
|
|
|
assert_instances_of($changesets, 'DifferentialChangeset');
|
|
|
|
assert_instances_of($vs_changesets, 'DifferentialChangeset');
|
|
|
|
|
2013-09-30 21:21:33 +02:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
2014-05-25 17:59:31 +02:00
|
|
|
id(new DifferentialHunkQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withChangesets($changesets)
|
|
|
|
->needAttachToChangesets(true)
|
|
|
|
->execute();
|
2012-06-28 19:12:20 +02:00
|
|
|
|
|
|
|
$diff = new DifferentialDiff();
|
2013-12-04 23:39:07 +01:00
|
|
|
$diff->attachChangesets($changesets);
|
2013-09-17 22:55:41 +02:00
|
|
|
$raw_changes = $diff->buildChangesList();
|
2012-06-28 19:12:20 +02:00
|
|
|
$changes = array();
|
2013-09-17 22:55:41 +02:00
|
|
|
foreach ($raw_changes as $changedict) {
|
2012-06-28 19:12:20 +02:00
|
|
|
$changes[] = ArcanistDiffChange::newFromDictionary($changedict);
|
|
|
|
}
|
|
|
|
|
2013-09-30 21:21:33 +02:00
|
|
|
$loader = id(new PhabricatorFileBundleLoader())
|
|
|
|
->setViewer($viewer);
|
|
|
|
|
|
|
|
$bundle = ArcanistBundle::newFromChanges($changes);
|
|
|
|
$bundle->setLoadFileDataCallback(array($loader, 'loadFileData'));
|
2012-06-28 19:12:20 +02:00
|
|
|
|
|
|
|
$vcs = $repository ? $repository->getVersionControlSystem() : null;
|
|
|
|
switch ($vcs) {
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
2012-07-09 19:38:25 +02:00
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
2012-06-28 19:12:20 +02:00
|
|
|
$raw_diff = $bundle->toGitPatch();
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
|
|
|
default:
|
|
|
|
$raw_diff = $bundle->toUnifiedDiff();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-07-09 19:38:25 +02:00
|
|
|
$request_uri = $this->getRequest()->getRequestURI();
|
2012-06-28 19:12:20 +02:00
|
|
|
|
2012-07-09 19:38:25 +02:00
|
|
|
// this ends up being something like
|
|
|
|
// D123.diff
|
|
|
|
// or the verbose
|
|
|
|
// D123.vs123.id123.whitespaceignore-all.diff
|
|
|
|
// lame but nice to include these options
|
|
|
|
$file_name = ltrim($request_uri->getPath(), '/').'.';
|
|
|
|
foreach ($request_uri->getQueryParams() as $key => $value) {
|
|
|
|
if ($key == 'download') {
|
|
|
|
continue;
|
2012-06-28 19:12:20 +02:00
|
|
|
}
|
2012-07-09 19:38:25 +02:00
|
|
|
$file_name .= $key.$value.'.';
|
2012-06-28 19:12:20 +02:00
|
|
|
}
|
2012-07-09 19:38:25 +02:00
|
|
|
$file_name .= 'diff';
|
|
|
|
|
|
|
|
$file = PhabricatorFile::buildFromFileDataOrHash(
|
|
|
|
$raw_diff,
|
|
|
|
array(
|
|
|
|
'name' => $file_name,
|
2013-12-30 20:27:02 +01:00
|
|
|
'ttl' => (60 * 60 * 24),
|
|
|
|
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
2012-07-09 19:38:25 +02:00
|
|
|
));
|
2012-06-28 19:12:20 +02:00
|
|
|
|
2013-12-30 20:27:02 +01:00
|
|
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
2014-09-04 21:51:33 +02:00
|
|
|
$file->attachToObject($revision->getPHID());
|
2013-12-30 20:27:02 +01:00
|
|
|
unset($unguarded);
|
|
|
|
|
2014-08-20 00:53:15 +02:00
|
|
|
return $file->getRedirectResponse();
|
2012-06-28 19:12:20 +02:00
|
|
|
}
|
2014-02-12 23:05:40 +01:00
|
|
|
|
|
|
|
private function buildTransactions(
|
|
|
|
DifferentialRevision $revision,
|
2014-02-14 01:03:23 +01:00
|
|
|
DifferentialDiff $left_diff,
|
2015-04-22 00:32:23 +02:00
|
|
|
DifferentialDiff $right_diff,
|
|
|
|
array $old_ids,
|
|
|
|
array $new_ids) {
|
2014-07-23 02:03:09 +02:00
|
|
|
|
Transactions - deploy buildTransactionTimeline to remaining applications
Summary:
Ref T4712. Specifically...
- Differential
- needed getApplicationTransactionViewObject() implemented
- Audit
- needed getApplicationTransactionViewObject() implemented
- Repository
- one object needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true)
- Ponder
- BONUS BUG FIX - leaving a comment on an answer had a bad redirect URI
- both PonderQuestion and PonderAnswer needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on both "history" controllers
- left a "TODO" on buildAnswers on the question view controller, which is non-standard and should be re-written eventually
- Phortune
- BONUS BUG FIX - fix new user "createNewAccount" code to not fatal
- PhortuneAccount, PhortuneMerchant, and PhortuneCart needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on Account view, merchant view, and cart view controller
- Fund
- Legalpad
- Nuance
- NuanceSource needed PhabricatorApplicationTransactionInterface implemented
- Releeph (this product is kind of a mess...)
- HACKQUEST - had to manually create an arcanist project to even be able to make a "product" and get started...!
- BONUS BUG FIX - make sure to "setName" on product edit
- ReleephProject (should be ReleepProduct...?), ReleephBranch, and ReleepRequest needed PhabricatorApplicationTransactionInterface implemented
- Harbormaster
- HarbormasterBuildable, HarbormasterBuild, HarbormasterBuildPlan, and HarbormasterBuildStep all needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) all over the place
Test Plan: foreach application, viewed the timeline(s) and made sure they still rendered
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T4712
Differential Revision: https://secure.phabricator.com/D10925
2014-12-04 00:35:47 +01:00
|
|
|
$timeline = $this->buildTransactionTimeline(
|
|
|
|
$revision,
|
2014-12-04 22:58:52 +01:00
|
|
|
new DifferentialTransactionQuery(),
|
|
|
|
$engine = null,
|
|
|
|
array(
|
|
|
|
'left' => $left_diff->getID(),
|
|
|
|
'right' => $right_diff->getID(),
|
2015-04-22 00:32:23 +02:00
|
|
|
'old' => implode(',', $old_ids),
|
|
|
|
'new' => implode(',', $new_ids),
|
2014-12-04 22:58:52 +01:00
|
|
|
));
|
2014-02-12 23:05:40 +01:00
|
|
|
|
|
|
|
return $timeline;
|
|
|
|
}
|
|
|
|
|
2014-02-22 00:10:58 +01:00
|
|
|
private function buildRevisionWarnings(
|
|
|
|
DifferentialRevision $revision,
|
2014-07-02 13:58:51 +02:00
|
|
|
PhabricatorCustomFieldList $field_list,
|
|
|
|
array $warning_handle_map,
|
2014-02-22 00:10:58 +01:00
|
|
|
array $handles) {
|
|
|
|
|
|
|
|
$warnings = array();
|
2014-07-02 13:58:51 +02:00
|
|
|
foreach ($field_list->getFields() as $key => $field) {
|
|
|
|
$phids = idx($warning_handle_map, $key, array());
|
|
|
|
$field_handles = array_select_keys($handles, $phids);
|
|
|
|
$field_warnings = $field->getWarningsForRevisionHeader($field_handles);
|
|
|
|
foreach ($field_warnings as $warning) {
|
|
|
|
$warnings[] = $warning;
|
|
|
|
}
|
2014-02-22 00:10:58 +01:00
|
|
|
}
|
|
|
|
|
2014-07-02 13:58:51 +02:00
|
|
|
return $warnings;
|
2014-02-22 00:10:58 +01:00
|
|
|
}
|
|
|
|
|
2015-06-16 17:53:40 +02:00
|
|
|
private function buildDiffDetailView(
|
|
|
|
array $diffs,
|
|
|
|
DifferentialRevision $revision,
|
|
|
|
PhabricatorCustomFieldList $field_list) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
|
|
|
$fields = array();
|
|
|
|
foreach ($field_list->getFields() as $field) {
|
|
|
|
if ($field->shouldAppearInDiffPropertyView()) {
|
|
|
|
$fields[] = $field;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$fields) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$property_lists = array();
|
2016-02-29 18:53:46 +01:00
|
|
|
foreach ($this->getDiffTabLabels($diffs) as $tab) {
|
|
|
|
list($label, $diff) = $tab;
|
2015-06-16 17:53:40 +02:00
|
|
|
|
|
|
|
$property_lists[] = array(
|
|
|
|
$label,
|
|
|
|
$this->buildDiffPropertyList($diff, $revision, $fields),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$box = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Diff Detail'))
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$last_tab = null;
|
|
|
|
foreach ($property_lists as $key => $property_list) {
|
|
|
|
list($tab_name, $list_view) = $property_list;
|
|
|
|
|
|
|
|
$tab = id(new PHUIListItemView())
|
|
|
|
->setKey($key)
|
|
|
|
->setName($tab_name);
|
|
|
|
|
|
|
|
$box->addPropertyList($list_view, $tab);
|
|
|
|
$last_tab = $tab;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($last_tab) {
|
|
|
|
$last_tab->setSelected(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $box;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildDiffPropertyList(
|
|
|
|
DifferentialDiff $diff,
|
|
|
|
DifferentialRevision $revision,
|
|
|
|
array $fields) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setObject($diff);
|
|
|
|
|
|
|
|
foreach ($fields as $field) {
|
|
|
|
$label = $field->renderDiffPropertyViewLabel($diff);
|
|
|
|
$value = $field->renderDiffPropertyViewValue($diff);
|
|
|
|
if ($value !== null) {
|
|
|
|
$view->addProperty($label, $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2015-10-14 00:46:12 +02:00
|
|
|
private function buildOperationsBox(DifferentialRevision $revision) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
|
|
|
// Save a query if we can't possibly have pending operations.
|
|
|
|
$repository = $revision->getRepository();
|
|
|
|
if (!$repository || !$repository->canPerformAutomation()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$operations = id(new DrydockRepositoryOperationQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withObjectPHIDs(array($revision->getPHID()))
|
2015-12-26 21:20:21 +01:00
|
|
|
->withIsDismissed(false)
|
2015-10-26 20:58:37 +01:00
|
|
|
->withOperationTypes(
|
|
|
|
array(
|
|
|
|
DrydockLandRepositoryOperation::OPCONST,
|
|
|
|
))
|
2015-10-14 00:46:12 +02:00
|
|
|
->execute();
|
|
|
|
if (!$operations) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2015-10-26 20:58:37 +01:00
|
|
|
$state_fail = DrydockRepositoryOperation::STATE_FAIL;
|
|
|
|
|
|
|
|
// We're going to show the oldest operation which hasn't failed, or the
|
|
|
|
// most recent failure if they're all failures.
|
|
|
|
$operations = msort($operations, 'getID');
|
|
|
|
foreach ($operations as $operation) {
|
|
|
|
if ($operation->getOperationState() != $state_fail) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-10-14 00:46:12 +02:00
|
|
|
|
2015-10-26 22:27:04 +01:00
|
|
|
// If we found a completed operation, don't render anything. We don't want
|
|
|
|
// to show an older error after the thing worked properly.
|
|
|
|
if ($operation->isDone()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2015-10-21 20:28:26 +02:00
|
|
|
$box_view = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Active Operations'));
|
2015-10-14 00:46:12 +02:00
|
|
|
|
2015-10-21 20:28:26 +02:00
|
|
|
return id(new DrydockRepositoryOperationStatusView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setBoxView($box_view)
|
|
|
|
->setOperation($operation);
|
2015-10-14 00:46:12 +02:00
|
|
|
}
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
private function buildUnitMessagesView(
|
|
|
|
$diff,
|
|
|
|
DifferentialRevision $revision) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
|
|
|
if (!$diff->getUnitMessages()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-03-11 03:14:22 +01:00
|
|
|
if (!$diff->getBuildable()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-02-29 18:53:46 +01:00
|
|
|
$interesting_messages = array();
|
|
|
|
foreach ($diff->getUnitMessages() as $message) {
|
|
|
|
switch ($message->getResult()) {
|
|
|
|
case ArcanistUnitTestResult::RESULT_PASS:
|
|
|
|
case ArcanistUnitTestResult::RESULT_SKIP:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$interesting_messages[] = $message;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$interesting_messages) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$excuse = null;
|
|
|
|
if ($diff->hasDiffProperty('arc:unit-excuse')) {
|
|
|
|
$excuse = $diff->getProperty('arc:unit-excuse');
|
|
|
|
}
|
|
|
|
|
|
|
|
return id(new HarbormasterUnitSummaryView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setExcuse($excuse)
|
|
|
|
->setBuildable($diff->getBuildable())
|
|
|
|
->setUnitMessages($diff->getUnitMessages())
|
|
|
|
->setLimit(5)
|
|
|
|
->setShowViewAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-27 23:55:52 +01:00
|
|
|
}
|