mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-29 02:02:40 +01:00
Split mercurial parsing and API
Summary: Move code to actually parse "hg" output into a separate class with some tests, so I can reuse it in the import scripts. We should probably do this for Git/SVN at some point, too. Test Plan: Ran unit tests, used this class in Phabricator importers, grepped for calls to removed private methods. Reviewers: Makinde, jungejason, nh, tuomaspelkonen, aran Reviewed By: Makinde CC: aran, Makinde Differential Revision: 942
This commit is contained in:
parent
c84d6255b4
commit
cbbd798e48
11 changed files with 322 additions and 105 deletions
|
@ -57,6 +57,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistListWorkflow' => 'workflow/list',
|
'ArcanistListWorkflow' => 'workflow/list',
|
||||||
'ArcanistMarkCommittedWorkflow' => 'workflow/mark-committed',
|
'ArcanistMarkCommittedWorkflow' => 'workflow/mark-committed',
|
||||||
'ArcanistMercurialAPI' => 'repository/api/mercurial',
|
'ArcanistMercurialAPI' => 'repository/api/mercurial',
|
||||||
|
'ArcanistMercurialParser' => 'repository/parser/mercurial',
|
||||||
|
'ArcanistMercurialParserTestCase' => 'repository/parser/mercurial/__tests__',
|
||||||
'ArcanistMergeWorkflow' => 'workflow/merge',
|
'ArcanistMergeWorkflow' => 'workflow/merge',
|
||||||
'ArcanistNoEffectException' => 'exception/usage/noeffect',
|
'ArcanistNoEffectException' => 'exception/usage/noeffect',
|
||||||
'ArcanistNoEngineException' => 'exception/usage/noengine',
|
'ArcanistNoEngineException' => 'exception/usage/noengine',
|
||||||
|
@ -123,6 +125,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistListWorkflow' => 'ArcanistBaseWorkflow',
|
'ArcanistListWorkflow' => 'ArcanistBaseWorkflow',
|
||||||
'ArcanistMarkCommittedWorkflow' => 'ArcanistBaseWorkflow',
|
'ArcanistMarkCommittedWorkflow' => 'ArcanistBaseWorkflow',
|
||||||
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
|
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
|
||||||
|
'ArcanistMercurialParserTestCase' => 'ArcanistPhutilTestCase',
|
||||||
'ArcanistMergeWorkflow' => 'ArcanistBaseWorkflow',
|
'ArcanistMergeWorkflow' => 'ArcanistBaseWorkflow',
|
||||||
'ArcanistNoEffectException' => 'ArcanistUsageException',
|
'ArcanistNoEffectException' => 'ArcanistUsageException',
|
||||||
'ArcanistNoEngineException' => 'ArcanistUsageException',
|
'ArcanistNoEngineException' => 'ArcanistUsageException',
|
||||||
|
|
|
@ -71,7 +71,7 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
list($stdout) = execx(
|
list($stdout) = execx(
|
||||||
'(cd %s && hg outgoing --branch `hg branch` --limit 1 --style default)',
|
'(cd %s && hg outgoing --branch `hg branch` --limit 1 --style default)',
|
||||||
$this->getPath());
|
$this->getPath());
|
||||||
$logs = $this->parseMercurialLog($stdout);
|
$logs = ArcanistMercurialParser::parseMercurialLog($stdout);
|
||||||
if (!count($logs)) {
|
if (!count($logs)) {
|
||||||
throw new ArcanistUsageException("You have no outgoing changes!");
|
throw new ArcanistUsageException("You have no outgoing changes!");
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
'(cd %s && hg parents --style default --rev %s)',
|
'(cd %s && hg parents --style default --rev %s)',
|
||||||
$this->getPath(),
|
$this->getPath(),
|
||||||
$oldest_rev);
|
$oldest_rev);
|
||||||
$parents_logs = $this->parseMercurialLog($stdout);
|
$parents_logs = ArcanistMercurialParser::parseMercurialLog($stdout);
|
||||||
$first_parent = head($parents_logs);
|
$first_parent = head($parents_logs);
|
||||||
if (!$first_parent) {
|
if (!$first_parent) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
|
@ -106,7 +106,7 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
$this->getPath(),
|
$this->getPath(),
|
||||||
$this->getRelativeCommit(),
|
$this->getRelativeCommit(),
|
||||||
$this->getWorkingCopyRevision());
|
$this->getWorkingCopyRevision());
|
||||||
$logs = $this->parseMercurialLog($info);
|
$logs = ArcanistMercurialParser::parseMercurialLog($info);
|
||||||
|
|
||||||
// Get rid of the first log, it's not actually part of the diff. "hg log"
|
// Get rid of the first log, it's not actually part of the diff. "hg log"
|
||||||
// is inclusive, while "hg diff" is exclusive.
|
// is inclusive, while "hg diff" is exclusive.
|
||||||
|
@ -182,7 +182,7 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
'(cd %s && hg status)',
|
'(cd %s && hg status)',
|
||||||
$this->getPath());
|
$this->getPath());
|
||||||
|
|
||||||
$working_status = $this->parseMercurialStatus($stdout);
|
$working_status = ArcanistMercurialParser::parseMercurialStatus($stdout);
|
||||||
foreach ($working_status as $path => $status) {
|
foreach ($working_status as $path => $status) {
|
||||||
$status |= self::FLAG_UNCOMMITTED;
|
$status |= self::FLAG_UNCOMMITTED;
|
||||||
if (!empty($status_map[$path])) {
|
if (!empty($status_map[$path])) {
|
||||||
|
@ -251,107 +251,6 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
return $stdout;
|
return $stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseMercurialStatus($status) {
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
$status = trim($status);
|
|
||||||
if (!strlen($status)) {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
$lines = explode("\n", $status);
|
|
||||||
foreach ($lines as $line) {
|
|
||||||
$flags = 0;
|
|
||||||
list($code, $path) = explode(' ', $line, 2);
|
|
||||||
switch ($code) {
|
|
||||||
case 'A':
|
|
||||||
$flags |= self::FLAG_ADDED;
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
$flags |= self::FLAG_REMOVED;
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
$flags |= self::FLAG_MODIFIED;
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
// This is "clean" and included only for completeness, these files
|
|
||||||
// have not been changed.
|
|
||||||
break;
|
|
||||||
case '!':
|
|
||||||
$flags |= self::FLAG_MISSING;
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
$flags |= self::FLAG_UNTRACKED;
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
// This is "ignored" and included only for completeness.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown Mercurial status '{$code}'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
$result[$path] = $flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function parseMercurialLog($log) {
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
$chunks = explode("\n\n", trim($log));
|
|
||||||
foreach ($chunks as $chunk) {
|
|
||||||
$commit = array();
|
|
||||||
$lines = explode("\n", $chunk);
|
|
||||||
foreach ($lines as $line) {
|
|
||||||
if (preg_match('/^(comparing with|searching for changes)/', $line)) {
|
|
||||||
// These are sent to stdout when you run "hg outgoing" although the
|
|
||||||
// format is otherwise identical to "hg log".
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
list($name, $value) = explode(':', $line, 2);
|
|
||||||
$value = trim($value);
|
|
||||||
switch ($name) {
|
|
||||||
case 'user':
|
|
||||||
$commit['user'] = $value;
|
|
||||||
break;
|
|
||||||
case 'date':
|
|
||||||
$commit['date'] = strtotime($value);
|
|
||||||
break;
|
|
||||||
case 'summary':
|
|
||||||
$commit['summary'] = $value;
|
|
||||||
break;
|
|
||||||
case 'changeset':
|
|
||||||
list($local, $rev) = explode(':', $value, 2);
|
|
||||||
$commit['local'] = $local;
|
|
||||||
$commit['rev'] = $rev;
|
|
||||||
break;
|
|
||||||
case 'parent':
|
|
||||||
if (empty($commit['parents'])) {
|
|
||||||
$commit['parents'] = array();
|
|
||||||
}
|
|
||||||
list($local, $rev) = explode(':', $value, 2);
|
|
||||||
$commit['parents'][] = array(
|
|
||||||
'local' => $local,
|
|
||||||
'rev' => $rev,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'branch':
|
|
||||||
$commit['branch'] = $value;
|
|
||||||
break;
|
|
||||||
case 'tag':
|
|
||||||
$commit['tag'] = $value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown Mercurial log field '{$name}'!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$result[] = $commit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getWorkingCopyRevision() {
|
private function getWorkingCopyRevision() {
|
||||||
// In Mercurial, "tip" means the tip of the current branch, not what's in
|
// In Mercurial, "tip" means the tip of the current branch, not what's in
|
||||||
// the working copy. The tip may be ahead of the working copy. We need to
|
// the working copy. The tip may be ahead of the working copy. We need to
|
||||||
|
|
|
@ -10,6 +10,7 @@ phutil_require_module('arcanist', 'exception/usage');
|
||||||
phutil_require_module('arcanist', 'parser/diff');
|
phutil_require_module('arcanist', 'parser/diff');
|
||||||
phutil_require_module('arcanist', 'parser/diff/changetype');
|
phutil_require_module('arcanist', 'parser/diff/changetype');
|
||||||
phutil_require_module('arcanist', 'repository/api/base');
|
phutil_require_module('arcanist', 'repository/api/base');
|
||||||
|
phutil_require_module('arcanist', 'repository/parser/mercurial');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'future/exec');
|
phutil_require_module('phutil', 'future/exec');
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
192
src/repository/parser/mercurial/ArcanistMercurialParser.php
Normal file
192
src/repository/parser/mercurial/ArcanistMercurialParser.php
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses output from various "hg" commands into structured data. This class
|
||||||
|
* provides low-level APIs for reading "hg" output.
|
||||||
|
*
|
||||||
|
* @task parse Parsing "hg" Output
|
||||||
|
* @group workingcopy
|
||||||
|
*/
|
||||||
|
final class ArcanistMercurialParser {
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Parsing "hg" Output )------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the output of "hg status".
|
||||||
|
*
|
||||||
|
* @param string The stdout from running an "hg status" command.
|
||||||
|
* @return dict Map of paths to ArcanistRepositoryAPI status flags.
|
||||||
|
* @task parse
|
||||||
|
*/
|
||||||
|
public static function parseMercurialStatus($stdout) {
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$stdout = trim($stdout);
|
||||||
|
if (!strlen($stdout)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = explode("\n", $stdout);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$flags = 0;
|
||||||
|
list($code, $path) = explode(' ', $line, 2);
|
||||||
|
switch ($code) {
|
||||||
|
case 'A':
|
||||||
|
$flags |= ArcanistRepositoryAPI::FLAG_ADDED;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
$flags |= ArcanistRepositoryAPI::FLAG_REMOVED;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
$flags |= ArcanistRepositoryAPI::FLAG_MODIFIED;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
// This is "clean" and included only for completeness, these files
|
||||||
|
// have not been changed.
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
$flags |= ArcanistRepositoryAPI::FLAG_MISSING;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
$flags |= ArcanistRepositoryAPI::FLAG_UNTRACKED;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
// This is "ignored" and included only for completeness.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown Mercurial status '{$code}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$path] = $flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the output of "hg log". This also parses "hg outgoing", "hg parents",
|
||||||
|
* and other similar commands. This assumes "--style default".
|
||||||
|
*
|
||||||
|
* @param string The stdout from running an "hg log" command.
|
||||||
|
* @return list List of dictionaries with commit information.
|
||||||
|
* @task parse
|
||||||
|
*/
|
||||||
|
public static function parseMercurialLog($stdout) {
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$stdout = trim($stdout);
|
||||||
|
if (!strlen($stdout)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunks = explode("\n\n", $stdout);
|
||||||
|
foreach ($chunks as $chunk) {
|
||||||
|
$commit = array();
|
||||||
|
$lines = explode("\n", $chunk);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
if (preg_match('/^(comparing with|searching for changes)/', $line)) {
|
||||||
|
// These are sent to stdout when you run "hg outgoing" although the
|
||||||
|
// format is otherwise identical to "hg log".
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list($name, $value) = explode(':', $line, 2);
|
||||||
|
$value = trim($value);
|
||||||
|
switch ($name) {
|
||||||
|
case 'user':
|
||||||
|
$commit['user'] = $value;
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
$commit['date'] = strtotime($value);
|
||||||
|
break;
|
||||||
|
case 'summary':
|
||||||
|
$commit['summary'] = $value;
|
||||||
|
break;
|
||||||
|
case 'changeset':
|
||||||
|
list($local, $rev) = explode(':', $value, 2);
|
||||||
|
$commit['local'] = $local;
|
||||||
|
$commit['rev'] = $rev;
|
||||||
|
break;
|
||||||
|
case 'parent':
|
||||||
|
if (empty($commit['parents'])) {
|
||||||
|
$commit['parents'] = array();
|
||||||
|
}
|
||||||
|
list($local, $rev) = explode(':', $value, 2);
|
||||||
|
$commit['parents'][] = array(
|
||||||
|
'local' => $local,
|
||||||
|
'rev' => $rev,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'branch':
|
||||||
|
$commit['branch'] = $value;
|
||||||
|
break;
|
||||||
|
case 'tag':
|
||||||
|
$commit['tag'] = $value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown Mercurial log field '{$name}'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result[] = $commit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the output of "hg branches".
|
||||||
|
*
|
||||||
|
* @param string The stdout from running an "hg branches" command.
|
||||||
|
* @return list A list of dictionaries with branch information.
|
||||||
|
* @task parse
|
||||||
|
*/
|
||||||
|
public static function parseMercurialBranches($stdout) {
|
||||||
|
$lines = explode("\n", trim($stdout));
|
||||||
|
|
||||||
|
$branches = array();
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$matches = null;
|
||||||
|
|
||||||
|
// Output of "hg branches" normally looks like:
|
||||||
|
//
|
||||||
|
// default 15101:a21ccf4412d5
|
||||||
|
//
|
||||||
|
// ...but may also have human-readable cues like:
|
||||||
|
//
|
||||||
|
// stable 15095:ec222a29bdf0 (inactive)
|
||||||
|
//
|
||||||
|
// See the unit tests for more examples.
|
||||||
|
$regexp = '/^([^ ]+)\s+(\d+):([a-f0-9]+)(\s|$)/';
|
||||||
|
|
||||||
|
if (!preg_match($regexp, $line, $matches)) {
|
||||||
|
throw new Exception("Failed to parse 'hg branches' output: {$line}");
|
||||||
|
}
|
||||||
|
$branches[$matches[1]] = array(
|
||||||
|
'local' => $matches[2],
|
||||||
|
'rev' => $matches[3],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $branches;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/repository/parser/mercurial/__init__.php
Normal file
12
src/repository/parser/mercurial/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('arcanist', 'repository/api/base');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('ArcanistMercurialParser.php');
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class ArcanistMercurialParserTestCase extends ArcanistPhutilTestCase {
|
||||||
|
|
||||||
|
public function testParseAll() {
|
||||||
|
$root = dirname(__FILE__).'/data/';
|
||||||
|
foreach (Filesystem::listDirectory($root) as $file) {
|
||||||
|
$this->parseData(
|
||||||
|
basename($file),
|
||||||
|
Filesystem::readFile($root.'/'.$file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseData($name, $data) {
|
||||||
|
switch ($name) {
|
||||||
|
case 'branches-basic.txt':
|
||||||
|
$output = ArcanistMercurialParser::parseMercurialBranches($data);
|
||||||
|
$this->assertEqual(
|
||||||
|
array('default', 'stable'),
|
||||||
|
array_keys($output));
|
||||||
|
$this->assertEqual(
|
||||||
|
array('a21ccf4412d5', 'ec222a29bdf0'),
|
||||||
|
array_values(ipull($output, 'rev')));
|
||||||
|
break;
|
||||||
|
case 'log-basic.txt':
|
||||||
|
$output = ArcanistMercurialParser::parseMercurialLog($data);
|
||||||
|
$this->assertEqual(
|
||||||
|
3,
|
||||||
|
count($output));
|
||||||
|
$this->assertEqual(
|
||||||
|
array('a21ccf4412d5', 'a051f8a6a7cc', 'b1f49efeab65'),
|
||||||
|
array_values(ipull($output, 'rev')));
|
||||||
|
break;
|
||||||
|
case 'log-empty.txt':
|
||||||
|
// Empty logs (e.g., "hg parents" for a root revision) should parse
|
||||||
|
// correctly.
|
||||||
|
$output = ArcanistMercurialParser::parseMercurialLog($data);
|
||||||
|
$this->assertEqual(
|
||||||
|
array(),
|
||||||
|
$output);
|
||||||
|
break;
|
||||||
|
case 'status-basic.txt':
|
||||||
|
$output = ArcanistMercurialParser::parseMercurialStatus($data);
|
||||||
|
$this->assertEqual(
|
||||||
|
4,
|
||||||
|
count($output));
|
||||||
|
$this->assertEqual(
|
||||||
|
array('changed', 'added', 'removed', 'untracked'),
|
||||||
|
array_keys($output));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("No test information for test data '{$name}'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/repository/parser/mercurial/__tests__/__init__.php
Normal file
16
src/repository/parser/mercurial/__tests__/__init__.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('arcanist', 'repository/parser/mercurial');
|
||||||
|
phutil_require_module('arcanist', 'unit/engine/phutil/testcase');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'filesystem');
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('ArcanistMercurialParserTestCase.php');
|
|
@ -0,0 +1,2 @@
|
||||||
|
default 15101:a21ccf4412d5
|
||||||
|
stable 15095:ec222a29bdf0 (inactive)
|
16
src/repository/parser/mercurial/__tests__/data/log-basic.txt
Normal file
16
src/repository/parser/mercurial/__tests__/data/log-basic.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
changeset: 15101:a21ccf4412d5
|
||||||
|
tag: tip
|
||||||
|
user: Greg Ward <greg@gerg.ca>
|
||||||
|
date: Wed Sep 14 22:28:27 2011 -0400
|
||||||
|
summary: share: allow trailing newline on .hg/sharedpath.
|
||||||
|
|
||||||
|
changeset: 15100:a051f8a6a7cc
|
||||||
|
user: Ben Hockey <neonstalwart@gmail.com>
|
||||||
|
date: Wed Sep 07 10:24:26 2011 -0400
|
||||||
|
summary: contrib: some support for named branches in zsh_completion (issue2988)
|
||||||
|
|
||||||
|
changeset: 15099:b1f49efeab65
|
||||||
|
user: Simon Heimberg <simohe@besonet.ch>
|
||||||
|
date: Wed Sep 14 17:06:33 2011 +0200
|
||||||
|
summary: test: test for options duplicate with global options
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
M changed
|
||||||
|
A added
|
||||||
|
! removed
|
||||||
|
? untracked
|
Loading…
Reference in a new issue