diff --git a/src/work/ArcanistWorkEngine.php b/src/work/ArcanistWorkEngine.php --- a/src/work/ArcanistWorkEngine.php +++ b/src/work/ArcanistWorkEngine.php @@ -198,18 +198,73 @@ ArcanistSymbolRef::HARDPOINT_OBJECT); $task_ref = $task_symbol->getObject(); + if (!$task_ref) { throw new PhutilArgumentUsageException( pht( 'No task "%s" exists, or you do not have permission to view it.', $symbol)); } + $monogram = $task_ref->getMonogram(); + $task_name = $task_ref->getName(); + $api = $this->getRepositoryAPI(); + + // Check if the branch exists + $existing_branches = + $api->execxLocal('branch --list \'%s-*\' --format \'%%(refname:short)\'' + , $monogram); + $existing_branches = trim($existing_branches[0]); + $existing_branches = explode("\n", $existing_branches); + $existing_branches = array_filter($existing_branches, function ($e) { + return $e !== ''; + }); + + $branch_name = ''; + if (count($existing_branches) === 1) { + $branch_name = trim($existing_branches[0]); + } else if (count($existing_branches) > 1 ) { + // error more than one branch + throw new InvalidArgumentException( + pht( + "More than one branch matching task ID '%s' exists.". + " Use 'git checkout' instead.", + $monogram)); + } - throw new Exception(pht('TODO: Implement this workflow.')); + if ($branch_name !== '') { + $api->execxLocal('checkout %s', $branch_name); + } else { + // TODO: break this out into named function in class ArcanistGitWorkEngine + // e.g. sanitizeBranchName($monogram, $task_name) + + // see https://git-scm.com/docs/git-check-ref-format + $pattern = + '#(^[./]+|//|/\.+|\.{2,}|@{|[/.]+$|^@$|[~^:\x00-\x20\x7F?*\[\\\\])#u'; + $branch_name = preg_replace($pattern, '-', $task_name); + $branch_name = trim($branch_name, '-'); + $branch_name = mb_convert_case($branch_name, MB_CASE_LOWER, 'UTF-8'); + $branch_name = $monogram.'-'.$branch_name; + // to reduce multiple '-' to single '-' + $branch_name = preg_replace('#-+#', '-', $branch_name); + // keep length to GitHub max + $branch_name = rtrim(mb_substr($branch_name, 0, 244), '-'); + + // below should work unless in detached HEAD state?? + $start = id($api)->getBranchName(); + if (!$start) { + // test detached HEAD?? + $start = id($api)->getWorkingCopyRevision(); + } + $this->newMarker($branch_name, $start); + } - $this->loadHardpoints( - $task_ref, - ArcanistTaskRef::HARDPOINT_REVISIONREFS); + return id(new ArcanistMarkerRef()) + ->setName($branch_name) + ->setMarkerType(ArcanistMarkerRef::TYPE_BRANCH); + /* $this->loadHardpoints( + $task_ref, + ArcanistTaskRef::HARDPOINT_REVISIONREFS); + */ } }