3 final class ReleephBranchTemplate
extends Phobject
{
5 const KEY
= 'releeph.default-branch-template';
8 private $branchDate = null;
12 public static function getDefaultTemplate() {
13 return PhabricatorEnv
::getEnvConfig(self
::KEY
);
16 public static function getRequiredDefaultTemplate() {
17 $template = self
::getDefaultTemplate();
19 throw new Exception(pht(
20 "Config setting '%s' must be set, ".
21 "or you must provide a branch-template for each project!",
27 public static function getFakeCommitHandleFor(
29 PhabricatorUser
$viewer) {
31 $repository = id(new PhabricatorRepositoryQuery())
33 ->withPHIDs(array($repository_phid))
36 $fake_handle = 'SOFAKE';
38 $fake_handle = id(new PhabricatorObjectHandle())
39 ->setName($repository->formatCommitName('100000000000'));
44 public function setCommitHandle(PhabricatorObjectHandle
$handle) {
45 $this->commitHandle
= $handle;
49 public function setBranchDate($branch_date) {
50 $this->branchDate
= $branch_date;
54 public function setReleephProjectName($project_name) {
55 $this->projectName
= $project_name;
59 public function setSymbolic($is_symbolic) {
60 $this->isSymbolic
= $is_symbolic;
64 public function interpolate($template) {
65 if (!$this->projectName
) {
66 return array('', array());
69 list($name, $name_errors) = $this->interpolateInner(
73 if ($this->isSymbolic
) {
74 return array($name, $name_errors);
76 $validate_errors = $this->validateAsBranchName($name);
77 $errors = array_merge($name_errors, $validate_errors);
78 return array($name, $errors);
83 * xsprintf() would be useful here, but that's for formatting concrete lists
84 * of things in a certain way...
86 * animal_printf('%A %A %A', $dog1, $dog2, $dog3);
88 * ...rather than interpolating percent-control-strings like strftime does.
90 private function interpolateInner($template, $is_symbolic) {
94 $safe_project_name = str_replace(' ', '-', $this->projectName
);
95 $short_commit_id = last(
96 preg_split('/r[A-Z]+/', $this->commitHandle
->getName()));
98 $interpolations = array();
99 for ($ii = 0; $ii < strlen($name); $ii++
) {
100 $char = substr($name, $ii, 1);
103 $prev = substr($name, $ii - 1, 1);
105 $next = substr($name, $ii +
1, 1);
106 if ($next && $char == '%' && $prev != '%') {
107 $interpolations[$ii] = $next;
111 $variable_interpolations = array();
113 $reverse_interpolations = $interpolations;
114 krsort($reverse_interpolations);
116 if ($this->branchDate
) {
117 $branch_date = $this->branchDate
;
119 $branch_date = $this->commitHandle
->getTimestamp();
122 foreach ($reverse_interpolations as $position => $code) {
126 $replacement = $this->commitHandle
->getName();
131 $replacement = $short_commit_id;
136 $replacement = $safe_project_name;
137 $is_variable = false;
141 $replacement = strtolower($safe_project_name);
142 $is_variable = false;
146 // Format anything else using strftime()
147 $replacement = strftime("%{$code}", $branch_date);
153 $variable_interpolations[] = $code;
155 $name = substr_replace($name, $replacement, $position, 2);
158 if (!$is_symbolic && !$variable_interpolations) {
159 $errors[] = pht("Include additional interpolations that aren't static!");
162 return array($name, $errors);
165 private function validateAsBranchName($name) {
168 if (preg_match('{^/}', $name) ||
preg_match('{/$}', $name)) {
169 $errors[] = pht("Branches cannot begin or end with '%s'", '/');
172 if (preg_match('{//+}', $name)) {
173 $errors[] = pht("Branches cannot contain multiple consecutive '%s'", '/');
176 $parts = array_filter(explode('/', $name));
177 foreach ($parts as $index => $part) {
179 if (preg_match('{^\.}', $part) ||
preg_match('{\.$}', $part)) {
180 $errors[] = pht("Path components cannot begin or end with '%s'", '.');
181 } else if (preg_match('{^(?!\w)}', $part)) {
182 $errors[] = pht('Path components must begin with an alphanumeric.');
183 } else if (!preg_match('{^\w ([\w-_%\.]* [\w-_%])?$}x', $part)) {
185 "Path components may only contain alphanumerics ".
186 "or '%s', '%s' or '%s'.",