public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $viewer_is_anonymous = !$user->isLoggedIn(); $revision = id(new DifferentialRevisionQuery())->withIDs(array($this->revisionID))->setViewer($request->getUser())->needRelationships(true)->needReviewerStatus(true)->needReviewerAuthority(true)->executeOne(); if (!$revision) { return new Aphront404Response(); } $diffs = id(new DifferentialDiffQuery())->setViewer($request->getUser())->withRevisionIDs(array($this->revisionID))->execute(); $diffs = array_reverse($diffs, $preserve_keys = true); if (!$diffs) { throw new Exception(pht('This revision has no diffs. Something has gone quite wrong.')); } $revision->attachActiveDiff(last($diffs)); $diff_vs = $request->getInt('vs'); $target_id = $request->getInt('id'); $target = idx($diffs, $target_id, end($diffs)); $target_manual = $target; if (!$target_id) { foreach ($diffs as $diff) { if ($diff->getCreationMethod() != 'commit') { $target_manual = $diff; } } } if (empty($diffs[$diff_vs])) { $diff_vs = null; } $repository = null; $repository_phid = $target->getRepositoryPHID(); if ($repository_phid) { if ($repository_phid == $revision->getRepositoryPHID()) { $repository = $revision->getRepository(); } else { $repository = id(new PhabricatorRepositoryQuery())->setViewer($user)->withPHIDs(array($repository_phid))->executeOne(); } } list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository); if ($request->getExists('download')) { return $this->buildRawDiffResponse($revision, $changesets, $vs_changesets, $vs_map, $repository); } $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; } } $props = id(new DifferentialDiffProperty())->loadAllWhere('diffID = %d', $target_manual->getID()); $props = mpull($props, 'getData', 'getName'); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID())); foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $field_list = PhabricatorCustomField::getObjectFields($revision, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($user); $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; } } $handles = $this->loadViewerHandles($object_phids); $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = count($changesets); $warning = new PHUIInfoView(); $warning->setTitle(pht('Very Large Diff')); $warning->setSeverity(PHUIInfoView::SEVERITY_WARNING); $warning->appendChild(hsprintf('%s <strong>%s</strong>', pht('This diff is very large and affects %s files. ' . 'You may load each file individually or ', new PhutilNumber($count)), phutil_tag('a', array('class' => 'button grey', 'href' => $request_uri->alter('large', 'true')->setFragment('toc')), pht('Show All Files Inline')))); $warning = $warning->render(); $old = array_select_keys($changesets, $old_ids); $new = array_select_keys($changesets, $new_ids); $query = id(new DifferentialInlineCommentQuery())->setViewer($user)->needHidden(true)->withRevisionPHIDs(array($revision->getPHID())); $inlines = $query->execute(); $inlines = $query->adjustInlinesForChangesets($inlines, $old, $new, $revision); $visible_changesets = array(); foreach ($inlines as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { $visible_changesets[$changeset_id] = $changesets[$changeset_id]; } } } else { $warning = null; $visible_changesets = $changesets; } $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)); if ($commit_hashes) { $commits_for_links = id(new DiffusionCommitQuery())->setViewer($user)->withIdentifiers($commit_hashes)->execute(); $commits_for_links = mpull($commits_for_links, null, 'getCommitIdentifier'); } else { $commits_for_links = array(); } $revision_detail = id(new DifferentialRevisionDetailView())->setUser($user)->setRevision($revision)->setDiff(end($diffs))->setCustomFields($field_list)->setURI($request->getRequestURI()); $actions = $this->getRevisionActions($revision); $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_MOST); $repository = $revision->getRepository(); if ($repository) { $symbol_indexes = $this->buildSymbolIndexes($repository, $visible_changesets); } else { $symbol_indexes = array(); } $revision_detail->setActions($actions); $revision_detail->setUser($user); $revision_detail_box = $revision_detail->render(); $revision_warnings = $this->buildRevisionWarnings($revision, $field_list, $warning_handle_map, $handles); if ($revision_warnings) { $revision_warnings = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($revision_warnings); $revision_detail_box->setInfoView($revision_warnings); } $detail_diffs = array_select_keys($diffs, array($diff_vs, $target->getID())); $detail_diffs = mpull($detail_diffs, null, 'getPHID'); $buildables = id(new HarbormasterBuildableQuery())->setViewer($user)->withBuildablePHIDs(array_keys($detail_diffs))->withManualBuildables(false)->needBuilds(true)->needTargets(true)->execute(); $buildables = mpull($buildables, null, 'getBuildablePHID'); foreach ($detail_diffs as $diff_phid => $detail_diff) { $detail_diff->attachBuildable(idx($buildables, $diff_phid)); } $diff_detail_box = $this->buildDiffDetailView($detail_diffs, $revision, $field_list); $comment_view = $this->buildTransactions($revision, $diff_vs ? $diffs[$diff_vs] : $target, $target, $old_ids, $new_ids); if (!$viewer_is_anonymous) { $comment_view->setQuoteRef('D' . $revision->getID()); $comment_view->setQuoteTargetID('comment-content'); } $wrap_id = celerity_generate_unique_node_id(); $comment_view = phutil_tag('div', array('id' => $wrap_id), $comment_view); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($changesets); $changeset_view->setVisibleChangesets($visible_changesets); if (!$viewer_is_anonymous) { $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/'); } $changeset_view->setStandaloneURI('/differential/changeset/'); $changeset_view->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new'); $changeset_view->setUser($user); $changeset_view->setDiff($target); $changeset_view->setRenderingReferences($rendering_references); $changeset_view->setVsMap($vs_map); $changeset_view->setWhitespace($whitespace); if ($repository) { $changeset_view->setRepository($repository); } $changeset_view->setSymbolIndexes($symbol_indexes); $changeset_view->setTitle(pht('Diff %s', $target->getID())); $diff_history = id(new DifferentialRevisionUpdateHistoryView())->setUser($user)->setDiffs($diffs)->setSelectedVersusDiffID($diff_vs)->setSelectedDiffID($target->getID())->setSelectedWhitespace($whitespace)->setCommitsForLinks($commits_for_links); $local_view = id(new DifferentialLocalCommitsView())->setUser($user)->setLocalCommits(idx($props, 'local:commits'))->setCommitsForLinks($commits_for_links); if ($repository) { $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository); } else { $other_revisions = array(); } $other_view = null; if ($other_revisions) { $other_view = $this->renderOtherRevisions($other_revisions); } $toc_view = $this->buildTableOfContents($changesets, $visible_changesets, $target->loadCoverageMap($user)); $comment_form = null; if (!$viewer_is_anonymous) { $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID()); $reviewers = array(); $ccs = array(); if ($draft) { $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); } } $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $review_warnings = array(); foreach ($field_list->getFields() as $field) { $review_warnings[] = $field->getWarningsForDetailView(); } $review_warnings = array_mergev($review_warnings); if ($review_warnings) { $review_warnings_panel = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($review_warnings); $comment_form->setInfoView($review_warnings_panel); } $comment_form->setActions($this->getRevisionCommentActions($revision)); $action_uri = $this->getApplicationURI('comment/save/' . $revision->getID() . '/'); $comment_form->setActionURI($action_uri); $comment_form->setUser($user); $comment_form->setDraft($draft); $comment_form->setReviewers(mpull($reviewers, 'getFullName', 'getPHID')); $comment_form->setCCs(mpull($ccs, 'getFullName', 'getPHID')); // 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); } $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); Javelin::initBehavior('differential-user-select'); $page_pane = id(new DifferentialPrimaryPaneView())->setID($pane_id)->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)); } if ($comment_form) { $page_pane->appendChild($comment_form); } else { // TODO: For now, just use this to get "Login to Comment". $page_pane->appendChild(id(new PhabricatorApplicationTransactionCommentView())->setUser($user)->setRequestURI($request->getRequestURI())); } $object_id = 'D' . $revision->getID(); $content = array($revision_detail_box, $diff_detail_box, $page_pane); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($object_id, '/' . $object_id); $prefs = $user->loadPreferences(); $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); $nav->appendChild($content); $nav->setCrumbs($crumbs); $content = $nav; } else { array_unshift($content, $crumbs); } return $this->buildApplicationPage($content, array('title' => $object_id . ' ' . $revision->getTitle(), 'pageObjects' => array($revision->getPHID()))); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $viewer_is_anonymous = !$user->isLoggedIn(); $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { return new Aphront404Response(); } $revision->loadRelationships(); $diffs = $revision->loadDiffs(); if (!$diffs) { throw new Exception("This revision has no diffs. Something has gone quite wrong."); } $diff_vs = $request->getInt('vs'); $target = end($diffs); $target_id = $request->getInt('id'); if ($target_id) { if (isset($diffs[$target_id])) { $target = $diffs[$target_id]; } } $diffs = mpull($diffs, null, 'getID'); if (empty($diffs[$diff_vs])) { $diff_vs = null; } list($aux_fields, $props) = $this->loadAuxiliaryFieldsAndProperties($revision, $target, array('local:commits')); list($changesets, $vs_map, $rendering_references) = $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target); $comments = $revision->loadComments(); $comments = array_merge($this->getImplicitComments($revision), $comments); $all_changesets = $changesets; $inlines = $this->loadInlineComments($comments, $all_changesets); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID()), mpull($comments, 'getAuthorPHID')); foreach ($comments as $comment) { $metadata = $comment->getMetadata(); $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS); if ($added_reviewers) { foreach ($added_reviewers as $phid) { $object_phids[] = $phid; } } $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS); if ($added_ccs) { foreach ($added_ccs as $phid) { $object_phids[] = $phid; } } } foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $aux_phids = array(); foreach ($aux_fields as $key => $aux_field) { $aux_phids[$key] = $aux_field->getRequiredHandlePHIDsForRevisionView(); } $object_phids = array_merge($object_phids, array_mergev($aux_phids)); $object_phids = array_unique($object_phids); $handles = id(new PhabricatorObjectHandleData($object_phids))->loadHandles(); foreach ($aux_fields as $key => $aux_field) { // Make sure each field only has access to handles it specifically // requested, not all handles. Otherwise you can get a field which works // only in the presence of other fields. $aux_field->setHandles(array_select_keys($handles, $aux_phids[$key])); } $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = number_format(count($changesets)); $warning = new AphrontErrorView(); $warning->setTitle('Very Large Diff'); $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $warning->setWidth(AphrontErrorView::WIDTH_WIDE); $warning->appendChild("<p>This diff is very large and affects {$count} files. Use " . "Table of Contents to open files in a standalone view. " . "<strong>" . phutil_render_tag('a', array('href' => $request_uri->alter('large', 'true')), 'Show All Files Inline') . "</strong>"); $warning = $warning->render(); $visible_changesets = array(); } else { $warning = null; $visible_changesets = $changesets; } $revision_detail = new DifferentialRevisionDetailView(); $revision_detail->setRevision($revision); $revision_detail->setAuxiliaryFields($aux_fields); $actions = $this->getRevisionActions($revision); $custom_renderer_class = PhabricatorEnv::getEnvConfig('differential.revision-custom-detail-renderer'); if ($custom_renderer_class) { // TODO: build a better version of the action links and deprecate the // whole DifferentialRevisionDetailRenderer class. PhutilSymbolLoader::loadClass($custom_renderer_class); $custom_renderer = newv($custom_renderer_class, array()); $actions = array_merge($actions, $custom_renderer->generateActionLinks($revision, $target)); } $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_ALL); $arc_project = $target->loadArcanistProject(); if ($arc_project) { $symbol_indexes = $this->buildSymbolIndexes($target, $arc_project, $visible_changesets); $repository = $arc_project->loadRepository(); } else { $symbol_indexes = array(); $repository = null; } $revision_detail->setActions($actions); $revision_detail->setUser($user); $comment_view = new DifferentialRevisionCommentListView(); $comment_view->setComments($comments); $comment_view->setHandles($handles); $comment_view->setInlineComments($inlines); $comment_view->setChangesets($all_changesets); $comment_view->setUser($user); $comment_view->setTargetDiff($target); $comment_view->setVersusDiffID($diff_vs); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($visible_changesets); $changeset_view->setEditable(!$viewer_is_anonymous); $changeset_view->setStandaloneViews(true); $changeset_view->setRevision($revision); $changeset_view->setDiff($target); $changeset_view->setRenderingReferences($rendering_references); $changeset_view->setWhitespace($whitespace); if ($repository) { $changeset_view->setRepository($repository, $target); } $changeset_view->setSymbolIndexes($symbol_indexes); $diff_history = new DifferentialRevisionUpdateHistoryView(); $diff_history->setDiffs($diffs); $diff_history->setSelectedVersusDiffID($diff_vs); $diff_history->setSelectedDiffID($target->getID()); $diff_history->setSelectedWhitespace($whitespace); $diff_history->setUser($user); $local_view = new DifferentialLocalCommitsView(); $local_view->setUser($user); $local_view->setLocalCommits(idx($props, 'local:commits')); $toc_view = new DifferentialDiffTableOfContentsView(); $toc_view->setChangesets($changesets); $toc_view->setStandaloneViewLink(empty($visible_changesets)); $toc_view->setVsMap($vs_map); $toc_view->setRevisionID($revision->getID()); $toc_view->setWhitespace($whitespace); if (!$viewer_is_anonymous) { $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID()); if ($draft) { $draft = $draft->getDraft(); } else { $draft = null; } $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $comment_form->setActions($this->getRevisionCommentActions($revision)); $comment_form->setActionURI('/differential/comment/save/'); $comment_form->setUser($user); $comment_form->setDraft($draft); } $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); $page_pane = id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets($changesets)->setID($pane_id)->appendChild($revision_detail->render() . $comment_view->render() . $diff_history->render() . $warning . $local_view->render() . $toc_view->render() . $changeset_view->render()); if ($comment_form) { $page_pane->appendChild($comment_form->render()); } return $this->buildStandardPageResponse($page_pane, array('title' => 'D' . $revision->getID() . ' ' . $revision->getTitle())); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $viewer_is_anonymous = !$user->isLoggedIn(); $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { return new Aphront404Response(); } $revision->loadRelationships(); $diffs = $revision->loadDiffs(); if (!$diffs) { throw new Exception("This revision has no diffs. Something has gone quite wrong."); } $diff_vs = $request->getInt('vs'); $target_id = $request->getInt('id'); $target = idx($diffs, $target_id, end($diffs)); $target_manual = $target; if (!$target_id) { foreach ($diffs as $diff) { if ($diff->getCreationMethod() != 'commit') { $target_manual = $diff; } } } if (empty($diffs[$diff_vs])) { $diff_vs = null; } $arc_project = $target->loadArcanistProject(); $repository = $arc_project ? $arc_project->loadRepository() : null; list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository); if ($request->getExists('download')) { return $this->buildRawDiffResponse($changesets, $vs_changesets, $vs_map, $repository); } list($aux_fields, $props) = $this->loadAuxiliaryFieldsAndProperties($revision, $target_manual, array('local:commits', 'arc:lint', 'arc:unit')); $comments = $revision->loadComments(); $comments = array_merge($this->getImplicitComments($revision, reset($diffs)), $comments); $all_changesets = $changesets; $inlines = $this->loadInlineComments($comments, $all_changesets); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID()), mpull($comments, 'getAuthorPHID')); foreach ($comments as $comment) { $metadata = $comment->getMetadata(); $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS); if ($added_reviewers) { foreach ($added_reviewers as $phid) { $object_phids[] = $phid; } } $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS); if ($added_ccs) { foreach ($added_ccs as $phid) { $object_phids[] = $phid; } } } foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $aux_phids = array(); foreach ($aux_fields as $key => $aux_field) { $aux_phids[$key] = $aux_field->getRequiredHandlePHIDsForRevisionView(); } $object_phids = array_merge($object_phids, array_mergev($aux_phids)); $object_phids = array_unique($object_phids); $handles = id(new PhabricatorObjectHandleData($object_phids))->loadHandles(); foreach ($aux_fields as $key => $aux_field) { // Make sure each field only has access to handles it specifically // requested, not all handles. Otherwise you can get a field which works // only in the presence of other fields. $aux_field->setHandles(array_select_keys($handles, $aux_phids[$key])); } $reviewer_warning = null; $has_live_reviewer = false; foreach ($revision->getReviewers() as $reviewer) { if (!$handles[$reviewer]->isDisabled()) { $has_live_reviewer = true; } } if (!$has_live_reviewer) { $reviewer_warning = new AphrontErrorView(); $reviewer_warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $reviewer_warning->setTitle('No Active Reviewers'); if ($revision->getReviewers()) { $reviewer_warning->appendChild('<p>All specified reviewers are disabled. You may want to add ' . 'some new reviewers.</p>'); } else { $reviewer_warning->appendChild('<p>This revision has no specified reviewers. You may want to ' . 'add some.</p>'); } } $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = number_format(count($changesets)); $warning = new AphrontErrorView(); $warning->setTitle('Very Large Diff'); $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $warning->setWidth(AphrontErrorView::WIDTH_WIDE); $warning->appendChild("<p>This diff is very large and affects {$count} files. Load " . "each file individually. " . "<strong>" . phutil_render_tag('a', array('href' => $request_uri->alter('large', 'true')->setFragment('toc')), 'Show All Files Inline') . "</strong>"); $warning = $warning->render(); $my_inlines = id(new DifferentialInlineComment())->loadAllWhere('revisionID = %d AND commentID IS NULL AND authorPHID = %s AND ' . 'changesetID IN (%Ld)', $this->revisionID, $user->getPHID(), mpull($changesets, 'getID')); $visible_changesets = array(); foreach ($inlines + $my_inlines as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { $visible_changesets[$changeset_id] = $changesets[$changeset_id]; } } if (!empty($props['arc:lint'])) { $changeset_paths = mpull($changesets, null, 'getFilename'); foreach ($props['arc:lint'] as $lint) { $changeset = idx($changeset_paths, $lint['path']); if ($changeset) { $visible_changesets[$changeset->getID()] = $changeset; } } } } else { $warning = null; $visible_changesets = $changesets; } $revision_detail = new DifferentialRevisionDetailView(); $revision_detail->setRevision($revision); $revision_detail->setAuxiliaryFields($aux_fields); $actions = $this->getRevisionActions($revision); $custom_renderer_class = PhabricatorEnv::getEnvConfig('differential.revision-custom-detail-renderer'); if ($custom_renderer_class) { // TODO: build a better version of the action links and deprecate the // whole DifferentialRevisionDetailRenderer class. $custom_renderer = newv($custom_renderer_class, array()); $custom_renderer->setDiff($target); if ($diff_vs) { $custom_renderer->setVSDiff($diffs[$diff_vs]); } $actions = array_merge($actions, $custom_renderer->generateActionLinks($revision, $target_manual)); } $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_ALL); if ($arc_project) { list($symbol_indexes, $project_phids) = $this->buildSymbolIndexes($arc_project, $visible_changesets); } else { $symbol_indexes = array(); $project_phids = null; } $revision_detail->setActions($actions); $revision_detail->setUser($user); $comment_view = new DifferentialRevisionCommentListView(); $comment_view->setComments($comments); $comment_view->setHandles($handles); $comment_view->setInlineComments($inlines); $comment_view->setChangesets($all_changesets); $comment_view->setUser($user); $comment_view->setTargetDiff($target); $comment_view->setVersusDiffID($diff_vs); if ($arc_project) { Javelin::initBehavior('repository-crossreference', array('section' => $comment_view->getID(), 'projects' => $project_phids)); } $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($changesets); $changeset_view->setVisibleChangesets($visible_changesets); if (!$viewer_is_anonymous) { $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/'); } $changeset_view->setStandaloneURI('/differential/changeset/'); $changeset_view->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new'); $changeset_view->setUser($user); $changeset_view->setDiff($target); $changeset_view->setRenderingReferences($rendering_references); $changeset_view->setVsMap($vs_map); $changeset_view->setWhitespace($whitespace); if ($repository) { $changeset_view->setRepository($repository); } $changeset_view->setSymbolIndexes($symbol_indexes); $diff_history = new DifferentialRevisionUpdateHistoryView(); $diff_history->setDiffs($diffs); $diff_history->setSelectedVersusDiffID($diff_vs); $diff_history->setSelectedDiffID($target->getID()); $diff_history->setSelectedWhitespace($whitespace); $diff_history->setUser($user); $local_view = new DifferentialLocalCommitsView(); $local_view->setUser($user); $local_view->setLocalCommits(idx($props, 'local:commits')); if ($repository) { $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository); } else { $other_revisions = array(); } $other_view = null; if ($other_revisions) { $other_view = $this->renderOtherRevisions($other_revisions); } $toc_view = new DifferentialDiffTableOfContentsView(); $toc_view->setChangesets($changesets); $toc_view->setVisibleChangesets($visible_changesets); $toc_view->setRenderingReferences($rendering_references); $toc_view->setUnitTestData(idx($props, 'arc:unit', array())); if ($repository) { $toc_view->setRepository($repository); } $toc_view->setDiff($target); $toc_view->setUser($user); $toc_view->setRevisionID($revision->getID()); $toc_view->setWhitespace($whitespace); $comment_form = null; if (!$viewer_is_anonymous) { $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID()); if ($draft) { $draft = $draft->getDraft(); } else { $draft = null; } $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $comment_form->setAuxFields($aux_fields); $comment_form->setActions($this->getRevisionCommentActions($revision)); $comment_form->setActionURI('/differential/comment/save/'); $comment_form->setUser($user); $comment_form->setDraft($draft); } $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); Javelin::initBehavior('differential-user-select'); $page_pane = id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets($changesets)->setID($pane_id)->appendChild($comment_view->render() . $diff_history->render() . $warning . $local_view->render() . $toc_view->render() . $other_view . $changeset_view->render()); if ($comment_form) { $page_pane->appendChild($comment_form->render()); } PhabricatorFeedStoryNotification::updateObjectNotificationViews($user, $revision->getPHID()); $top_anchor = id(new PhabricatorAnchorView())->setAnchorName('top')->setNavigationMarker(true); $nav = $this->buildSideNavView($revision, $changesets); $nav->selectFilter(''); $nav->appendChild(array($reviewer_warning, $top_anchor, $revision_detail, $page_pane)); return $this->buildApplicationPage($nav, array('title' => 'D' . $revision->getID() . ' ' . $revision->getTitle())); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { return new Aphront404Response(); } $revision->loadRelationships(); $diffs = $revision->loadDiffs(); if (!$diffs) { throw new Exception("This revision has no diffs. Something has gone quite wrong."); } $diff_vs = $request->getInt('vs'); $target = end($diffs); $target_id = $request->getInt('id'); if ($target_id) { if (isset($diffs[$target_id])) { $target = $diffs[$target_id]; } } $diffs = mpull($diffs, null, 'getID'); if (empty($diffs[$diff_vs])) { $diff_vs = null; } list($changesets, $vs_map, $rendering_references) = $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target); $comments = $revision->loadComments(); $comments = array_merge($this->getImplicitComments($revision), $comments); $all_changesets = $changesets; $inlines = $this->loadInlineComments($comments, $all_changesets); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID()), mpull($comments, 'getAuthorPHID')); foreach ($comments as $comment) { $metadata = $comment->getMetadata(); $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS); if ($added_reviewers) { foreach ($added_reviewers as $phid) { $object_phids[] = $phid; } } $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS); if ($added_ccs) { foreach ($added_ccs as $phid) { $object_phids[] = $phid; } } } if ($target->getArcanistProjectPHID()) { $object_phids[] = $target->getArcanistProjectPHID(); } foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $object_phids = array_unique($object_phids); $handles = id(new PhabricatorObjectHandleData($object_phids))->loadHandles(); $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = number_format(count($changesets)); $warning = new AphrontErrorView(); $warning->setTitle('Very Large Diff'); $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $warning->setWidth(AphrontErrorView::WIDTH_WIDE); $warning->appendChild("<p>This diff is very large and affects {$count} files. Use " . "Table of Contents to open files in a standalone view. " . "<strong>" . phutil_render_tag('a', array('href' => $request_uri->alter('large', 'true')), 'Show All Files Inline') . "</strong>"); $warning = $warning->render(); $visible_changesets = array(); } else { $warning = null; $visible_changesets = $changesets; } $diff_properties = id(new DifferentialDiffProperty())->loadAllWhere('diffID = %d AND name IN (%Ls)', $target->getID(), array('arc:lint', 'arc:unit')); $diff_properties = mpull($diff_properties, 'getData', 'getName'); $revision_detail = new DifferentialRevisionDetailView(); $revision_detail->setRevision($revision); $custom_renderer_class = PhabricatorEnv::getEnvConfig('differential.revision-custom-detail-renderer'); if ($custom_renderer_class) { PhutilSymbolLoader::loadClass($custom_renderer_class); $custom_renderer = newv($custom_renderer_class, array()); } else { $custom_renderer = null; } $properties = $this->getRevisionProperties($revision, $target, $handles, $diff_properties); if ($custom_renderer) { $properties = array_merge($properties, $custom_renderer->generateProperties($revision, $target)); } $revision_detail->setProperties($properties); $actions = $this->getRevisionActions($revision); if ($custom_renderer) { $actions = array_merge($actions, $custom_renderer->generateActionLinks($revision, $target)); } $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_ALL); $revision_detail->setActions($actions); $revision_detail->setUser($user); $comment_view = new DifferentialRevisionCommentListView(); $comment_view->setComments($comments); $comment_view->setHandles($handles); $comment_view->setInlineComments($inlines); $comment_view->setChangesets($all_changesets); $comment_view->setUser($user); $comment_view->setTargetDiff($target); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($visible_changesets); $changeset_view->setEditable(true); $changeset_view->setStandaloneViews(true); $changeset_view->setRevision($revision); $changeset_view->setRenderingReferences($rendering_references); $changeset_view->setWhitespace($whitespace); $diff_history = new DifferentialRevisionUpdateHistoryView(); $diff_history->setDiffs($diffs); $diff_history->setSelectedVersusDiffID($diff_vs); $diff_history->setSelectedDiffID($target->getID()); $diff_history->setSelectedWhitespace($whitespace); $toc_view = new DifferentialDiffTableOfContentsView(); $toc_view->setChangesets($changesets); $toc_view->setStandaloneViewLink(empty($visible_changesets)); $toc_view->setVsMap($vs_map); $toc_view->setRevisionID($revision->getID()); $toc_view->setWhitespace($whitespace); $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID()); if ($draft) { $draft = $draft->getDraft(); } else { $draft = null; } $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $comment_form->setActions($this->getRevisionCommentActions($revision)); $comment_form->setActionURI('/differential/comment/save/'); $comment_form->setUser($user); $comment_form->setDraft($draft); $this->updateViewTime($user->getPHID(), $revision->getPHID()); $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); return $this->buildStandardPageResponse(id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets($changesets)->setID($pane_id)->appendChild($revision_detail->render() . $comment_view->render() . $diff_history->render() . $warning . $toc_view->render() . $changeset_view->render() . $comment_form->render()), array('title' => 'D' . $revision->getID() . ' ' . $revision->getTitle())); }