@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

In the "Version Information" panel, try to include branchpoints

Summary:
Fixes T12040. In T12039, a user running local patches followed the report instructions as far as grabbing version information, but didn't update or revert their local changes or try against a clean install before reporting.

This obviously isn't ideal for us, but it's understandable (grabbing version information is much easier than upgrading/reverting), and we can do better about making this information useful: when compiling version information, try to figure out the branchpoint from a known upstream `master` branch by listing remotes, then running `git merge-base` against them.

Additionally, explicitly document that we want upstream hashes. We have to have a fallback case in this document anyway (for when you can't get to Config) so hopefully this makes it more likely that we get useful information in initial reports.

Test Plan: {F2229574}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12040

Differential Revision: https://secure.phabricator.com/D17103

+157 -7
+134 -7
src/applications/config/controller/PhabricatorConfigVersionController.php
··· 39 39 $versions = $this->loadVersions($viewer); 40 40 41 41 $version_property_list = id(new PHUIPropertyListView()); 42 - foreach ($versions as $name => $version) { 43 - $version_property_list->addProperty($name, $version); 42 + foreach ($versions as $name => $info) { 43 + $version = $info['version']; 44 + 45 + if ($info['branchpoint']) { 46 + $display = pht( 47 + '%s (branched from %s on %s)', 48 + $version, 49 + $info['branchpoint'], 50 + $info['upstream']); 51 + } else { 52 + $display = $version; 53 + } 54 + 55 + $version_property_list->addProperty($name, $display); 44 56 } 45 57 46 58 $phabricator_root = dirname(phutil_get_library_root('phabricator')); ··· 67 79 $other_libraries = array_diff($all_libraries, $specs); 68 80 $specs = array_merge($specs, $other_libraries); 69 81 70 - $futures = array(); 82 + $log_futures = array(); 83 + $remote_futures = array(); 84 + 71 85 foreach ($specs as $lib) { 72 86 $root = dirname(phutil_get_library_root($lib)); 73 - $futures[$lib] = 74 - id(new ExecFuture('git log --format=%s -n 1 --', '%H %ct')) 87 + 88 + $log_command = csprintf( 89 + 'git log --format=%s -n 1 --', 90 + '%H %ct'); 91 + 92 + $remote_command = csprintf( 93 + 'git remote -v'); 94 + 95 + $log_futures[$lib] = id(new ExecFuture('%C', $log_command)) 96 + ->setCWD($root); 97 + 98 + $remote_futures[$lib] = id(new ExecFuture('%C', $remote_command)) 99 + ->setCWD($root); 100 + } 101 + 102 + $all_futures = array_merge($log_futures, $remote_futures); 103 + 104 + id(new FutureIterator($all_futures)) 105 + ->resolveAll(); 106 + 107 + // A repository may have a bunch of remotes, but we're only going to look 108 + // for remotes we host to try to figure out where this repository branched. 109 + $upstream_pattern = '(github\.com/phacility/|secure\.phabricator\.com/)'; 110 + 111 + $upstream_futures = array(); 112 + $lib_upstreams = array(); 113 + foreach ($specs as $lib) { 114 + $remote_future = $remote_futures[$lib]; 115 + 116 + list($err, $stdout) = $remote_future->resolve(); 117 + if ($err) { 118 + // If this fails for whatever reason, just move on. 119 + continue; 120 + } 121 + 122 + // These look like this, with a tab separating the first two fields: 123 + // remote-name http://remote.uri/ (push) 124 + 125 + $upstreams = array(); 126 + 127 + $remotes = phutil_split_lines($stdout, false); 128 + foreach ($remotes as $remote) { 129 + $remote_pattern = '/^([^\t]+)\t([^ ]+) \(([^)]+)\)\z/'; 130 + $matches = null; 131 + if (!preg_match($remote_pattern, $remote, $matches)) { 132 + continue; 133 + } 134 + 135 + // Remote URIs are either "push" or "fetch": we only care about "fetch" 136 + // URIs. 137 + $type = $matches[3]; 138 + if ($type != 'fetch') { 139 + continue; 140 + } 141 + 142 + $uri = $matches[2]; 143 + $is_upstream = preg_match($upstream_pattern, $uri); 144 + if (!$is_upstream) { 145 + continue; 146 + } 147 + 148 + $name = $matches[1]; 149 + $upstreams[$name] = $name; 150 + } 151 + 152 + // If we have several suitable upstreams, try to pick the one named 153 + // "origin", if it exists. Otherwise, just pick the first one. 154 + if (isset($upstreams['origin'])) { 155 + $upstream = $upstreams['origin']; 156 + } else if ($upstreams) { 157 + $upstream = head($upstreams); 158 + } else { 159 + $upstream = null; 160 + } 161 + 162 + if (!$upstream) { 163 + continue; 164 + } 165 + 166 + $lib_upstreams[$lib] = $upstream; 167 + 168 + $merge_base_command = csprintf( 169 + 'git merge-base HEAD %s/master --', 170 + $upstream); 171 + 172 + $root = dirname(phutil_get_library_root($lib)); 173 + 174 + $upstream_futures[$lib] = id(new ExecFuture('%C', $merge_base_command)) 75 175 ->setCWD($root); 176 + } 177 + 178 + if ($upstream_futures) { 179 + id(new FutureIterator($upstream_futures)) 180 + ->resolveAll(); 76 181 } 77 182 78 183 $results = array(); 79 - foreach ($futures as $key => $future) { 184 + foreach ($log_futures as $lib => $future) { 80 185 list($err, $stdout) = $future->resolve(); 81 186 if (!$err) { 82 187 list($hash, $epoch) = explode(' ', $stdout); ··· 84 189 } else { 85 190 $version = pht('Unknown'); 86 191 } 87 - $results[$key] = $version; 192 + 193 + $result = array( 194 + 'version' => $version, 195 + 'upstream' => null, 196 + 'branchpoint' => null, 197 + ); 198 + 199 + $upstream_future = idx($upstream_futures, $lib); 200 + if ($upstream_future) { 201 + list($err, $stdout) = $upstream_future->resolve(); 202 + if (!$err) { 203 + $branchpoint = trim($stdout); 204 + if (strlen($branchpoint)) { 205 + // We only list a branchpoint if it differs from HEAD. 206 + if ($branchpoint != $hash) { 207 + $result['upstream'] = $lib_upstreams[$lib]; 208 + $result['branchpoint'] = trim($stdout); 209 + } 210 + } 211 + } 212 + } 213 + 214 + $results[$lib] = $result; 88 215 } 89 216 90 217 return $results;
+23
src/docs/contributor/version.diviner
··· 49 49 prevents you from reaching the version reporting screen. 50 50 51 51 52 + Running a Fork? 53 + =============== 54 + 55 + If you've forked Phabricator and have local commits, please make sure you are 56 + reporting upstream commit hashes, not local commit hashes. The UI will attempt 57 + to figure out where you branched from, but it may not be able to in all cases. 58 + 59 + If you report local commit hashes instead of upstream commit hashes we can not 60 + go look up the commit hashes to figure out which changes they correspond to, so 61 + we can not use that information to determine out how old your install is or 62 + which patches you are missing. 63 + 64 + In most cases, you can find the upstream commit you've branched from like this: 65 + 66 + ``` 67 + $ git merge-base HEAD origin/master 68 + ```` 69 + 70 + Note that if you report a bug and have local commits, we will almost always ask 71 + you to reproduce the issue against a clean copy of Phabricator before we 72 + continue. You can get help faster by doing this //before// reporting an issue. 73 + 74 + 52 75 Next Steps 53 76 ========== 54 77