@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<?php
2
3final class DiffusionMergedCommitsQueryConduitAPIMethod
4 extends DiffusionQueryConduitAPIMethod {
5
6 public function getAPIMethodName() {
7 return 'diffusion.mergedcommitsquery';
8 }
9
10 public function getMethodDescription() {
11 return pht(
12 'Merged commit information for a specific commit in a repository.');
13 }
14
15 protected function defineReturnType() {
16 return 'array';
17 }
18
19 protected function defineCustomParamTypes() {
20 return array(
21 'commit' => 'required string',
22 'limit' => 'optional int',
23 );
24 }
25
26 private function getLimit(ConduitAPIRequest $request) {
27 // TODO: Paginate this sensibly at some point.
28 return $request->getValue('limit', 4096);
29 }
30
31 protected function getGitResult(ConduitAPIRequest $request) {
32 $drequest = $this->getDiffusionRequest();
33 $repository = $drequest->getRepository();
34 $commit = $request->getValue('commit');
35 $limit = $this->getLimit($request);
36
37 list($parents) = $repository->execxLocalCommand(
38 'log -n 1 %s %s --',
39 '--format=%P',
40 gitsprintf('%s', $commit));
41
42 $parents = preg_split('/\s+/', trim($parents));
43 if (count($parents) < 2) {
44 // This is not a merge commit, so it doesn't merge anything.
45 return array();
46 }
47
48 // Get all of the commits which are not reachable from the first parent.
49 // These are the commits this change merges.
50
51 $first_parent = head($parents);
52 list($logs) = $repository->execxLocalCommand(
53 'log -n %d %s %s %s --',
54 // NOTE: "+ 1" accounts for the merge commit itself.
55 $limit + 1,
56 '--format=%H',
57 gitsprintf('%s', $commit),
58 gitsprintf('%s', '^'.$first_parent));
59
60 $hashes = explode("\n", trim($logs));
61
62 // Remove the merge commit.
63 $hashes = array_diff($hashes, array($commit));
64
65 $history = DiffusionQuery::loadHistoryForCommitIdentifiers(
66 $hashes,
67 $drequest);
68 return mpull($history, 'toDictionary');
69 }
70
71 protected function getMercurialResult(ConduitAPIRequest $request) {
72 $drequest = $this->getDiffusionRequest();
73 $repository = $drequest->getRepository();
74 $commit = $request->getValue('commit');
75 $limit = $this->getLimit($request);
76
77 list($parents) = $repository->execxLocalCommand(
78 'parents --template=%s --rev %s',
79 '{node}\\n',
80 hgsprintf('%s', $commit));
81 $parents = explode("\n", trim($parents));
82
83 if (count($parents) < 2) {
84 // Not a merge commit.
85 return array();
86 }
87
88 // NOTE: In Git, the first parent is the "mainline". In Mercurial, the
89 // second parent is the "mainline" (the way 'git merge' and 'hg merge'
90 // work is also reversed).
91
92 $last_parent = last($parents);
93 list($logs) = $repository->execxLocalCommand(
94 'log --template=%s --follow --limit %d --rev %s:0 --prune %s --',
95 '{node}\\n',
96 $limit + 1,
97 $commit,
98 $last_parent);
99
100 $hashes = explode("\n", trim($logs));
101
102 // Remove the merge commit.
103 $hashes = array_diff($hashes, array($commit));
104
105 $history = DiffusionQuery::loadHistoryForCommitIdentifiers(
106 $hashes,
107 $drequest);
108 return mpull($history, 'toDictionary');
109 }
110
111}