Skip to content

Commit 8f3b342

Browse files
author
epriestley
committed
Improve several Diffusion UI error states
Summary: Give users better errors and UI: - For subpath SVN repositories, default the path to the subdirectory, not to "/". This makes the home screen useful and things generally less confusing. - For unparsed commits, show a more descriptive error message without the "blah blah" silliness. - For paths outside of the subpath parse tree, short circuit into an appropriate error message. - For foreign SVN stub commits (see D892), show an explicit message. Test Plan: Looked at unparsed commits, subpath repositories, foreign stub commits, and paths outside of the subpath parse tree. Received sensible error messages. Reviewers: jungejason, nh, tuomaspelkonen, aran Reviewed By: jungejason CC: aran, jungejason Differential Revision: 894
1 parent 8b06d7d commit 8f3b342

File tree

8 files changed

+174
-78
lines changed

8 files changed

+174
-78
lines changed

src/applications/daemon/controller/workertaskdetail/PhabricatorWorkerTaskDetailController.php

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,35 @@ public function processRequest() {
4646
$data = id(new PhabricatorWorkerTaskData())->loadOneWhere(
4747
'id = %d',
4848
$task->getDataID());
49+
50+
$extra = null;
51+
switch ($task->getTaskClass()) {
52+
case 'PhabricatorRepositorySvnCommitChangeParserWorker':
53+
case 'PhabricatorRepositoryGitCommitChangeParserWorker':
54+
$commit_id = idx($data->getData(), 'commitID');
55+
if ($commit_id) {
56+
$commit = id(new PhabricatorRepositoryCommit())->load($commit_id);
57+
if ($commit) {
58+
$repository = id(new PhabricatorRepository())->load(
59+
$commit->getRepositoryID());
60+
if ($repository) {
61+
$extra =
62+
"<strong>NOTE:</strong> ".
63+
"You can manually retry this task by running this script:".
64+
"<pre>".
65+
"phabricator/\$ ./scripts/repository/parse_one_commit.php ".
66+
"r".
67+
phutil_escape_html($repository->getCallsign()).
68+
phutil_escape_html($commit->getCommitIdentifier()).
69+
"</pre>";
70+
}
71+
}
72+
}
73+
break;
74+
default:
75+
break;
76+
}
77+
4978
if ($data) {
5079
$data = json_encode($data->getData());
5180
}
@@ -75,14 +104,23 @@ public function processRequest() {
75104
->appendChild(
76105
id(new AphrontFormTextAreaControl())
77106
->setLabel('Data')
78-
->setValue($data))
107+
->setValue($data));
108+
109+
if ($extra) {
110+
$form->appendChild(
111+
id(new AphrontFormMarkupControl())
112+
->setLabel('More')
113+
->setValue($extra));
114+
}
115+
116+
$form
79117
->appendChild(
80118
id(new AphrontFormSubmitControl())
81119
->addCancelButton('/daemon/'));
82120

83121
$panel = new AphrontPanelView();
84122
$panel->setHeader('Task Detail');
85-
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
123+
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
86124
$panel->appendChild($form);
87125

88126
return $this->buildStandardPageResponse(

src/applications/daemon/controller/workertaskdetail/__init__.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@
77

88

99
phutil_require_module('phabricator', 'applications/daemon/controller/base');
10+
phutil_require_module('phabricator', 'applications/repository/storage/commit');
11+
phutil_require_module('phabricator', 'applications/repository/storage/repository');
1012
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/task');
1113
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/taskdata');
1214
phutil_require_module('phabricator', 'view/form/base');
15+
phutil_require_module('phabricator', 'view/form/control/markup');
1316
phutil_require_module('phabricator', 'view/form/control/static');
1417
phutil_require_module('phabricator', 'view/form/control/submit');
1518
phutil_require_module('phabricator', 'view/form/control/textarea');
1619
phutil_require_module('phabricator', 'view/form/error');
1720
phutil_require_module('phabricator', 'view/layout/panel');
1821

22+
phutil_require_module('phutil', 'markup');
1923
phutil_require_module('phutil', 'utils');
2024

2125

src/applications/diffusion/controller/browse/DiffusionBrowseController.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ public function processRequest() {
7575
$controller->setDiffusionRequest($drequest);
7676
return $this->delegateToController($controller);
7777
break;
78+
case DiffusionBrowseQuery::REASON_IS_UNTRACKED_PARENT:
79+
$subdir = $drequest->getRepository()->getDetail('svn-subpath');
80+
$title = 'Directory Not Tracked';
81+
$body =
82+
"This repository is configured to track only one subdirectory ".
83+
"of the entire repository ('".phutil_escape_html($subdir)."'), ".
84+
"but you aren't looking at something in that subdirectory, so no ".
85+
"information is available.";
86+
$severity = AphrontErrorView::SEVERITY_WARNING;
87+
break;
7888
default:
7989
throw new Exception("Unknown failure reason!");
8090
}

src/applications/diffusion/controller/browse/__init__.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
phutil_require_module('phabricator', 'view/form/error');
1515
phutil_require_module('phabricator', 'view/layout/panel');
1616

17+
phutil_require_module('phutil', 'markup');
1718
phutil_require_module('phutil', 'utils');
1819

1920

src/applications/diffusion/controller/commit/DiffusionCommitController.php

Lines changed: 96 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -44,31 +44,47 @@ public function processRequest() {
4444

4545
$commit_data = $drequest->loadCommitData();
4646

47-
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
48-
49-
require_celerity_resource('diffusion-commit-view-css');
50-
require_celerity_resource('phabricator-remarkup-css');
51-
52-
$property_table = $this->renderPropertyTable($commit, $commit_data);
53-
54-
$detail_panel->appendChild(
55-
'<div class="diffusion-commit-view">'.
56-
'<div class="diffusion-commit-dateline">'.
57-
'r'.$callsign.$commit->getCommitIdentifier().
58-
' &middot; '.
59-
phabricator_datetime($commit->getEpoch(), $user).
60-
'</div>'.
61-
'<h1>Revision Detail</h1>'.
62-
'<div class="diffusion-commit-details">'.
63-
$property_table.
64-
'<hr />'.
65-
'<div class="diffusion-commit-message phabricator-remarkup">'.
66-
$engine->markupText($commit_data->getCommitMessage()).
47+
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
48+
if ($is_foreign) {
49+
$subpath = $commit_data->getCommitDetail('svn-subpath');
50+
51+
$error_panel = new AphrontErrorView();
52+
$error_panel->setWidth(AphrontErrorView::WIDTH_WIDE);
53+
$error_panel->setTitle('Commit Not Tracked');
54+
$error_panel->setSeverity(AphrontErrorView::SEVERITY_WARNING);
55+
$error_panel->appendChild(
56+
"This Diffusion repository is configured to track only one ".
57+
"subdirectory of the entire Subversion repository, and this commit ".
58+
"didn't affect the tracked subdirectory ('".
59+
phutil_escape_html($subpath)."'), so no information is available.");
60+
$content[] = $error_panel;
61+
} else {
62+
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
63+
64+
require_celerity_resource('diffusion-commit-view-css');
65+
require_celerity_resource('phabricator-remarkup-css');
66+
67+
$property_table = $this->renderPropertyTable($commit, $commit_data);
68+
69+
$detail_panel->appendChild(
70+
'<div class="diffusion-commit-view">'.
71+
'<div class="diffusion-commit-dateline">'.
72+
'r'.$callsign.$commit->getCommitIdentifier().
73+
' &middot; '.
74+
phabricator_datetime($commit->getEpoch(), $user).
75+
'</div>'.
76+
'<h1>Revision Detail</h1>'.
77+
'<div class="diffusion-commit-details">'.
78+
$property_table.
79+
'<hr />'.
80+
'<div class="diffusion-commit-message phabricator-remarkup">'.
81+
$engine->markupText($commit_data->getCommitMessage()).
82+
'</div>'.
6783
'</div>'.
68-
'</div>'.
69-
'</div>');
84+
'</div>');
7085

71-
$content[] = $detail_panel;
86+
$content[] = $detail_panel;
87+
}
7288

7389
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
7490
$drequest);
@@ -103,6 +119,23 @@ public function processRequest() {
103119
phutil_escape_html($bad_commit['description']));
104120

105121
$content[] = $error_panel;
122+
} else if ($is_foreign) {
123+
// Don't render anything else.
124+
} else if (!count($changes)) {
125+
$no_changes = new AphrontErrorView();
126+
$no_changes->setWidth(AphrontErrorView::WIDTH_WIDE);
127+
$no_changes->setSeverity(AphrontErrorView::SEVERITY_WARNING);
128+
$no_changes->setTitle('Not Yet Parsed');
129+
// TODO: This can also happen with weird SVN changes that don't do
130+
// anything (or only alter properties?), although the real no-changes case
131+
// is extremely rare and might be impossible to produce organically. We
132+
// should probably write some kind of "Nothing Happened!" change into the
133+
// DB once we parse these changes so we can distinguish between
134+
// "not parsed yet" and "no changes".
135+
$no_changes->appendChild(
136+
"This commit hasn't been fully parsed yet (or doesn't affect any ".
137+
"paths).");
138+
$content[] = $no_changes;
106139
} else {
107140
$change_panel = new AphrontPanelView();
108141
$change_panel->setHeader("Changes (".number_format($count).")");
@@ -130,60 +163,52 @@ public function processRequest() {
130163

131164
$content[] = $change_panel;
132165

133-
if ($changes) {
134-
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
135-
$changes);
136-
137-
$vcs = $repository->getVersionControlSystem();
138-
switch ($vcs) {
139-
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
140-
$vcs_supports_directory_changes = true;
141-
break;
142-
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
143-
$vcs_supports_directory_changes = false;
144-
break;
145-
default:
146-
throw new Exception("Unknown VCS.");
147-
}
166+
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
167+
$changes);
168+
169+
$vcs = $repository->getVersionControlSystem();
170+
switch ($vcs) {
171+
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
172+
$vcs_supports_directory_changes = true;
173+
break;
174+
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
175+
$vcs_supports_directory_changes = false;
176+
break;
177+
default:
178+
throw new Exception("Unknown VCS.");
179+
}
148180

149-
$references = array();
150-
foreach ($changesets as $key => $changeset) {
151-
$file_type = $changeset->getFileType();
152-
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
153-
if (!$vcs_supports_directory_changes) {
154-
unset($changesets[$key]);
155-
continue;
156-
}
181+
$references = array();
182+
foreach ($changesets as $key => $changeset) {
183+
$file_type = $changeset->getFileType();
184+
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
185+
if (!$vcs_supports_directory_changes) {
186+
unset($changesets[$key]);
187+
continue;
157188
}
158-
159-
$branch = $drequest->getBranchURIComponent(
160-
$drequest->getBranch());
161-
$filename = $changeset->getFilename();
162-
$commit = $drequest->getCommit();
163-
$reference = "{$branch}{$filename};{$commit}";
164-
$references[$key] = $reference;
165189
}
166190

167-
$change_list = new DifferentialChangesetListView();
168-
$change_list->setChangesets($changesets);
169-
$change_list->setRenderingReferences($references);
170-
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
171-
172-
// TODO: This is pretty awkward, unify the CSS between Diffusion and
173-
// Differential better.
174-
require_celerity_resource('differential-core-view-css');
175-
$change_list =
176-
'<div class="differential-primary-pane">'.
177-
$change_list->render().
178-
'</div>';
179-
} else {
180-
$change_list =
181-
'<div style="margin: 2em; color: #666; padding: 1em;
182-
background: #eee;">'.
183-
'(no changes blah blah)'.
184-
'</div>';
191+
$branch = $drequest->getBranchURIComponent(
192+
$drequest->getBranch());
193+
$filename = $changeset->getFilename();
194+
$commit = $drequest->getCommit();
195+
$reference = "{$branch}{$filename};{$commit}";
196+
$references[$key] = $reference;
185197
}
186198

199+
$change_list = new DifferentialChangesetListView();
200+
$change_list->setChangesets($changesets);
201+
$change_list->setRenderingReferences($references);
202+
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
203+
204+
// TODO: This is pretty awkward, unify the CSS between Diffusion and
205+
// Differential better.
206+
require_celerity_resource('differential-core-view-css');
207+
$change_list =
208+
'<div class="differential-primary-pane">'.
209+
$change_list->render().
210+
'</div>';
211+
187212
$content[] = $change_list;
188213
}
189214

src/applications/diffusion/query/browse/base/DiffusionBrowseQuery.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ abstract class DiffusionBrowseQuery {
2525
protected $deletedAtCommit;
2626
protected $validityOnly;
2727

28-
const REASON_IS_FILE = 'is-file';
29-
const REASON_IS_DELETED = 'is-deleted';
30-
const REASON_IS_NONEXISTENT = 'nonexistent';
31-
const REASON_BAD_COMMIT = 'bad-commit';
32-
const REASON_IS_EMPTY = 'empty';
28+
const REASON_IS_FILE = 'is-file';
29+
const REASON_IS_DELETED = 'is-deleted';
30+
const REASON_IS_NONEXISTENT = 'nonexistent';
31+
const REASON_BAD_COMMIT = 'bad-commit';
32+
const REASON_IS_EMPTY = 'empty';
33+
const REASON_IS_UNTRACKED_PARENT = 'untracked-parent';
3334

3435
final private function __construct() {
3536
// <private>

src/applications/diffusion/query/browse/svn/DiffusionSvnBrowseQuery.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ protected function executeQuery() {
2525
$path = $drequest->getPath();
2626
$commit = $drequest->getCommit();
2727

28+
$subpath = $repository->getDetail('svn-subpath');
29+
if ($subpath && strncmp($subpath, $path, strlen($subpath))) {
30+
// If we have a subpath and the path isn't a child of it, it (almost
31+
// certainly) won't exist since we don't track commits which affect
32+
// it. (Even if it exists, return a consistent result.)
33+
$this->reason = self::REASON_IS_UNTRACKED_PARENT;
34+
return array();
35+
}
36+
2837
$conn_r = $repository->establishConnection('r');
2938

3039
$parent_path = dirname($path);

src/applications/diffusion/request/svn/DiffusionSvnRequest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ class DiffusionSvnRequest extends DiffusionRequest {
2020

2121
protected function initializeFromAphrontRequestDictionary(array $data) {
2222
parent::initializeFromAphrontRequestDictionary($data);
23+
24+
if ($this->path === null) {
25+
$subpath = $this->repository->getDetail('svn-subpath');
26+
if ($subpath) {
27+
$this->path = $subpath;
28+
}
29+
}
30+
2331
if (!strncmp($this->path, ':', 1)) {
2432
$this->path = substr($this->path, 1);
2533
$this->path = ltrim($this->path, '/');

0 commit comments

Comments
 (0)