~ubuntu-branches/ubuntu/wily/phabricator/wily

« back to all changes in this revision

Viewing changes to src/workflow/ArcanistCoverWorkflow.php

  • Committer: Package Import Robot
  • Author(s): Richard Sellam
  • Date: 2014-11-01 23:20:06 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20141101232006-mvlnp0cil67tsboe
Tags: upstream-0~git20141101/arcanist
Import upstream version 0~git20141101, component arcanist

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/**
 
4
 * Covers your professional reputation by blaming changes to locate reviewers.
 
5
 */
 
6
final class ArcanistCoverWorkflow extends ArcanistWorkflow {
 
7
 
 
8
  public function getWorkflowName() {
 
9
    return 'cover';
 
10
  }
 
11
 
 
12
  public function getCommandSynopses() {
 
13
    return phutil_console_format(<<<EOTEXT
 
14
      **cover** [--rev __revision__] [__path__ ...]
 
15
EOTEXT
 
16
      );
 
17
  }
 
18
 
 
19
  public function getCommandHelp() {
 
20
    return phutil_console_format(<<<EOTEXT
 
21
          Supports: svn, git, hg
 
22
          Cover your... professional reputation. Show blame for the lines you
 
23
          changed in your working copy (svn) or since some commit (hg, git).
 
24
          This will take a minute because blame takes a minute, especially under
 
25
          SVN.
 
26
EOTEXT
 
27
      );
 
28
  }
 
29
 
 
30
  public function getArguments() {
 
31
    return array(
 
32
      'rev' => array(
 
33
        'param'     => 'revision',
 
34
        'help'      => 'Cover changes since a specific revision.',
 
35
        'supports'  => array(
 
36
          'git',
 
37
          'hg',
 
38
        ),
 
39
        'nosupport' => array(
 
40
          'svn' => 'cover does not currently support --rev in svn.',
 
41
        ),
 
42
      ),
 
43
      '*' => 'paths',
 
44
    );
 
45
  }
 
46
 
 
47
  public function requiresWorkingCopy() {
 
48
    return true;
 
49
  }
 
50
 
 
51
  public function requiresConduit() {
 
52
    return false;
 
53
  }
 
54
 
 
55
  public function requiresAuthentication() {
 
56
    return false;
 
57
  }
 
58
 
 
59
  public function requiresRepositoryAPI() {
 
60
    return true;
 
61
  }
 
62
 
 
63
  public function run() {
 
64
    $repository_api = $this->getRepositoryAPI();
 
65
 
 
66
    $in_paths = $this->getArgument('paths');
 
67
    $in_rev = $this->getArgument('rev');
 
68
 
 
69
    if ($in_rev) {
 
70
      $this->parseBaseCommitArgument(array($in_rev));
 
71
    }
 
72
 
 
73
    $paths = $this->selectPathsForWorkflow(
 
74
      $in_paths,
 
75
      $in_rev,
 
76
      ArcanistRepositoryAPI::FLAG_UNTRACKED |
 
77
      ArcanistRepositoryAPI::FLAG_ADDED);
 
78
 
 
79
    if (!$paths) {
 
80
      throw new ArcanistNoEffectException(
 
81
        "You're covered, you didn't change anything.");
 
82
    }
 
83
 
 
84
    $covers = array();
 
85
    foreach ($paths as $path) {
 
86
      if (is_dir($repository_api->getPath($path))) {
 
87
        continue;
 
88
      }
 
89
 
 
90
      $lines = $this->getChangedLines($path, 'cover');
 
91
      if (!$lines) {
 
92
        continue;
 
93
      }
 
94
 
 
95
      $blame = $repository_api->getBlame($path);
 
96
      foreach ($lines as $line) {
 
97
        list($author, $revision) = idx($blame, $line, array(null, null));
 
98
        if (!$author) {
 
99
          continue;
 
100
        }
 
101
        if (!isset($covers[$author])) {
 
102
          $covers[$author] = array();
 
103
        }
 
104
        if (!isset($covers[$author][$path])) {
 
105
          $covers[$author][$path] = array(
 
106
            'lines'     => array(),
 
107
            'revisions' => array(),
 
108
          );
 
109
        }
 
110
        $covers[$author][$path]['lines'][] = $line;
 
111
        $covers[$author][$path]['revisions'][] = $revision;
 
112
      }
 
113
    }
 
114
 
 
115
    if (count($covers)) {
 
116
      foreach ($covers as $author => $files) {
 
117
        echo phutil_console_format(
 
118
          "**%s**\n",
 
119
          $author);
 
120
        foreach ($files as $file => $info) {
 
121
          $line_noun = pht('line(s)', count($info['lines']));
 
122
          $lines = $this->readableSequenceFromLineNumbers($info['lines']);
 
123
          echo "  {$file}: {$line_noun} {$lines}\n";
 
124
        }
 
125
      }
 
126
    } else {
 
127
      echo "You're covered, your changes didn't touch anyone else's code.\n";
 
128
    }
 
129
 
 
130
    return 0;
 
131
  }
 
132
 
 
133
  private function readableSequenceFromLineNumbers(array $array) {
 
134
    $sequence = array();
 
135
    $last = null;
 
136
    $seq  = null;
 
137
    $array = array_unique(array_map('intval', $array));
 
138
    sort($array);
 
139
    foreach ($array as $element) {
 
140
      if ($seq !== null && $element == ($seq + 1)) {
 
141
        $seq++;
 
142
        continue;
 
143
      }
 
144
 
 
145
      if ($seq === null) {
 
146
        $last = $element;
 
147
        $seq  = $element;
 
148
        continue;
 
149
      }
 
150
 
 
151
      if ($seq > $last) {
 
152
        $sequence[] = $last.'-'.$seq;
 
153
      } else {
 
154
        $sequence[] = $last;
 
155
      }
 
156
 
 
157
      $last = $element;
 
158
      $seq  = $element;
 
159
    }
 
160
    if ($last !== null && $seq > $last) {
 
161
      $sequence[] = $last.'-'.$seq;
 
162
    } else if ($last !== null) {
 
163
      $sequence[] = $element;
 
164
    }
 
165
 
 
166
    return implode(', ', $sequence);
 
167
  }
 
168
 
 
169
}