These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @link http://www.yiiframework.com/ |
||
4 | * @copyright Copyright (c) 2008 Yii Software LLC |
||
5 | * @license http://www.yiiframework.com/license/ |
||
6 | */ |
||
7 | |||
8 | namespace yii\build\controllers; |
||
9 | |||
10 | use Yii; |
||
11 | use yii\base\Exception; |
||
12 | use yii\console\Controller; |
||
13 | use yii\helpers\ArrayHelper; |
||
14 | use yii\helpers\Console; |
||
15 | use yii\helpers\FileHelper; |
||
16 | |||
17 | /** |
||
18 | * ReleaseController is there to help preparing releases. |
||
19 | * |
||
20 | * Get a version overview: |
||
21 | * |
||
22 | * ./build release/info |
||
23 | * |
||
24 | * run it with `--update` to fetch tags for all repos: |
||
25 | * |
||
26 | * ./build release/info --update |
||
27 | * |
||
28 | * Make a framework release (apps are always in line with framework): |
||
29 | * |
||
30 | * ./build release framework |
||
31 | * ./build release app-basic |
||
32 | * ./build release app-advanced |
||
33 | * |
||
34 | * Make an extension release (e.g. for redis): |
||
35 | * |
||
36 | * ./build release redis |
||
37 | * |
||
38 | * Be sure to check the help info for individual sub-commands: |
||
39 | * |
||
40 | * @author Carsten Brandt <[email protected]> |
||
41 | * @since 2.0 |
||
42 | */ |
||
43 | class ReleaseController extends Controller |
||
44 | { |
||
45 | public $defaultAction = 'release'; |
||
46 | |||
47 | /** |
||
48 | * @var string base path to use for releases. |
||
49 | */ |
||
50 | public $basePath; |
||
51 | /** |
||
52 | * @var bool whether to make actual changes. If true, it will run without changing or pushing anything. |
||
53 | */ |
||
54 | public $dryRun = false; |
||
55 | /** |
||
56 | * @var bool whether to fetch latest tags. |
||
57 | */ |
||
58 | public $update = false; |
||
59 | /** |
||
60 | * @var string override the default version. e.g. for major or patch releases. |
||
61 | */ |
||
62 | public $version; |
||
63 | |||
64 | |||
65 | public function options($actionID) |
||
66 | { |
||
67 | $options = ['basePath']; |
||
68 | if ($actionID === 'release') { |
||
69 | $options[] = 'dryRun'; |
||
70 | $options[] = 'version'; |
||
71 | } elseif ($actionID === 'sort-changelog') { |
||
72 | $options[] = 'version'; |
||
73 | } elseif ($actionID === 'info') { |
||
74 | $options[] = 'update'; |
||
75 | } |
||
76 | |||
77 | return array_merge(parent::options($actionID), $options); |
||
78 | } |
||
79 | |||
80 | |||
81 | public function beforeAction($action) |
||
82 | { |
||
83 | if (!$this->interactive) { |
||
84 | throw new Exception('Sorry, but releases should be run interactively to ensure you actually verify what you are doing ;)'); |
||
85 | } |
||
86 | if ($this->basePath === null) { |
||
87 | $this->basePath = \dirname(\dirname(__DIR__)); |
||
88 | } |
||
89 | $this->basePath = rtrim($this->basePath, '\\/'); |
||
90 | return parent::beforeAction($action); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Shows information about current framework and extension versions. |
||
95 | */ |
||
96 | public function actionInfo() |
||
97 | { |
||
98 | $items = [ |
||
99 | 'framework', |
||
100 | 'app-basic', |
||
101 | 'app-advanced', |
||
102 | ]; |
||
103 | $extensionPath = "{$this->basePath}/extensions"; |
||
104 | foreach (scandir($extensionPath) as $extension) { |
||
105 | if (ctype_alpha($extension) && is_dir($extensionPath . '/' . $extension)) { |
||
106 | $items[] = $extension; |
||
107 | } |
||
108 | } |
||
109 | |||
110 | if ($this->update) { |
||
111 | foreach ($items as $item) { |
||
112 | $this->stdout("fetching tags for $item..."); |
||
113 | if ($item === 'framework') { |
||
114 | $this->gitFetchTags((string)$this->basePath); |
||
115 | } elseif (strncmp('app-', $item, 4) === 0) { |
||
116 | $this->gitFetchTags("{$this->basePath}/apps/" . substr($item, 4)); |
||
117 | } else { |
||
118 | $this->gitFetchTags("{$this->basePath}/extensions/$item"); |
||
119 | } |
||
120 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
121 | } |
||
122 | } else { |
||
123 | $this->stdout("\nInformation may be outdated, re-run with `--update` to fetch latest tags.\n\n"); |
||
124 | } |
||
125 | |||
126 | $versions = $this->getCurrentVersions($items); |
||
127 | $nextVersions = $this->getNextVersions($versions, self::PATCH); |
||
128 | |||
129 | // print version table |
||
130 | $w = $this->minWidth(array_keys($versions)); |
||
131 | $this->stdout(str_repeat(' ', $w + 2) . "Current Version Next Version\n", Console::BOLD); |
||
132 | foreach ($versions as $ext => $version) { |
||
133 | $this->stdout($ext . str_repeat(' ', $w + 3 - mb_strlen($ext)) . $version . ''); |
||
134 | $this->stdout(str_repeat(' ', 17 - mb_strlen($version)) . $nextVersions[$ext] . "\n"); |
||
135 | } |
||
136 | } |
||
137 | |||
138 | private function minWidth($a) |
||
139 | { |
||
140 | $w = 1; |
||
141 | foreach ($a as $s) { |
||
142 | if (($l = mb_strlen($s)) > $w) { |
||
143 | $w = $l; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | return $w; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Automation tool for making Yii framework and official extension releases. |
||
152 | * |
||
153 | * Usage: |
||
154 | * |
||
155 | * To make a release, make sure your git is clean (no uncommitted changes) and run the following command in |
||
156 | * the yii dev repo root: |
||
157 | * |
||
158 | * ``` |
||
159 | * ./build/build release framework |
||
160 | * ``` |
||
161 | * |
||
162 | * or |
||
163 | * |
||
164 | * ``` |
||
165 | * ./build/build release redis,bootstrap,apidoc |
||
166 | * ``` |
||
167 | * |
||
168 | * You may use the `--dryRun` switch to test the command without changing or pushing anything: |
||
169 | * |
||
170 | * ``` |
||
171 | * ./build/build release redis --dryRun |
||
172 | * ``` |
||
173 | * |
||
174 | * The command will guide you through the complete release process including changing of files, |
||
175 | * committing and pushing them. Each git command must be confirmed and can be skipped individually. |
||
176 | * You may adjust changes in a separate shell or your IDE while the command is waiting for confirmation. |
||
177 | * |
||
178 | * @param array $what what do you want to release? this can either be: |
||
179 | * |
||
180 | * - an extension name such as `redis` or `bootstrap`, |
||
181 | * - an application indicated by prefix `app-`, e.g. `app-basic`, |
||
182 | * - or `framework` if you want to release a new version of the framework itself. |
||
183 | * |
||
184 | * @return int |
||
185 | */ |
||
186 | public function actionRelease(array $what) |
||
187 | { |
||
188 | if (\count($what) > 1) { |
||
189 | $this->stdout("Currently only one simultaneous release is supported.\n"); |
||
190 | return 1; |
||
191 | } |
||
192 | |||
193 | $this->stdout("This is the Yii release manager\n\n", Console::BOLD); |
||
194 | |||
195 | if ($this->dryRun) { |
||
196 | $this->stdout("Running in \"dry-run\" mode, nothing will actually be changed.\n\n", Console::BOLD, Console::FG_GREEN); |
||
197 | } |
||
198 | |||
199 | $this->validateWhat($what); |
||
200 | $versions = $this->getCurrentVersions($what); |
||
201 | |||
202 | if ($this->version !== null) { |
||
203 | // if a version is explicitly given |
||
204 | $newVersions = []; |
||
205 | foreach ($versions as $k => $v) { |
||
206 | $newVersions[$k] = $this->version; |
||
207 | } |
||
208 | } else { |
||
209 | // otherwise get next patch or minor |
||
210 | $newVersions = $this->getNextVersions($versions, self::PATCH); |
||
211 | } |
||
212 | |||
213 | $this->stdout("You are about to prepare a new release for the following things:\n\n"); |
||
214 | $this->printWhat($what, $newVersions, $versions); |
||
215 | $this->stdout("\n"); |
||
216 | |||
217 | $this->stdout("Before you make a release briefly go over the changes and check if you spot obvious mistakes:\n\n", Console::BOLD); |
||
218 | $gitDir = reset($what) === 'framework' ? 'framework/' : ''; |
||
219 | $gitVersion = $versions[reset($what)]; |
||
220 | if (strncmp('app-', reset($what), 4) !== 0) { |
||
221 | $this->stdout("- no accidentally added CHANGELOG lines for other versions than this one?\n\n git diff $gitVersion.. ${gitDir}CHANGELOG.md\n\n"); |
||
222 | $this->stdout("- are all new `@since` tags for this release version?\n"); |
||
223 | } |
||
224 | $this->stdout("- other issues with code changes?\n\n git diff -w $gitVersion.. ${gitDir}\n\n"); |
||
225 | $travisUrl = reset($what) === 'framework' ? '' : '-' . reset($what); |
||
226 | $this->stdout("- are unit tests passing on travis? https://travis-ci.org/yiisoft/yii2$travisUrl/builds\n"); |
||
227 | $this->stdout("- also make sure the milestone on github is complete and no issues or PRs are left open.\n\n"); |
||
228 | $this->printWhatUrls($what, $versions); |
||
229 | $this->stdout("\n"); |
||
230 | |||
231 | if (!$this->confirm('When you continue, this tool will run cleanup jobs and update the changelog as well as other files (locally). Continue?', false)) { |
||
0 ignored issues
–
show
|
|||
232 | $this->stdout("Canceled.\n"); |
||
233 | return 1; |
||
234 | } |
||
235 | |||
236 | foreach ($what as $ext) { |
||
237 | if ($ext === 'framework') { |
||
238 | $this->releaseFramework("{$this->basePath}/framework", $newVersions['framework']); |
||
239 | } elseif (strncmp('app-', $ext, 4) === 0) { |
||
240 | $this->releaseApplication(substr($ext, 4), "{$this->basePath}/apps/" . substr($ext, 4), $newVersions[$ext]); |
||
241 | } else { |
||
242 | $this->releaseExtension($ext, "{$this->basePath}/extensions/$ext", $newVersions[$ext]); |
||
243 | } |
||
244 | } |
||
245 | |||
246 | return 0; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * This will generate application packages for download page. |
||
251 | * |
||
252 | * Usage: |
||
253 | * |
||
254 | * ``` |
||
255 | * ./build/build release/package app-basic |
||
256 | * ``` |
||
257 | * |
||
258 | * @param array $what what do you want to package? this can either be: |
||
259 | * |
||
260 | * - an application indicated by prefix `app-`, e.g. `app-basic`, |
||
261 | * |
||
262 | * @return int |
||
263 | */ |
||
264 | public function actionPackage(array $what) |
||
265 | { |
||
266 | $this->validateWhat($what, ['app']); |
||
267 | $versions = $this->getCurrentVersions($what); |
||
268 | |||
269 | $this->stdout("You are about to generate packages for the following things:\n\n"); |
||
270 | foreach ($what as $ext) { |
||
271 | if (strncmp('app-', $ext, 4) === 0) { |
||
272 | $this->stdout(' - '); |
||
273 | $this->stdout(substr($ext, 4), Console::FG_RED); |
||
274 | $this->stdout(' application version '); |
||
275 | } elseif ($ext === 'framework') { |
||
276 | $this->stdout(' - Yii Framework version '); |
||
277 | } else { |
||
278 | $this->stdout(' - '); |
||
279 | $this->stdout($ext, Console::FG_RED); |
||
280 | $this->stdout(' extension version '); |
||
281 | } |
||
282 | $this->stdout($versions[$ext], Console::BOLD); |
||
283 | $this->stdout("\n"); |
||
284 | } |
||
285 | $this->stdout("\n"); |
||
286 | |||
287 | $packagePath = "{$this->basePath}/packages"; |
||
288 | $this->stdout("Packages will be stored in $packagePath\n\n"); |
||
289 | |||
290 | if (!$this->confirm('Continue?', false)) { |
||
0 ignored issues
–
show
The expression
$this->confirm('Continue?', false) of type boolean|null is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
291 | $this->stdout("Canceled.\n"); |
||
292 | return 1; |
||
293 | } |
||
294 | |||
295 | foreach ($what as $ext) { |
||
296 | if ($ext === 'framework') { |
||
297 | throw new Exception('Can not package framework.'); |
||
298 | } elseif (strncmp('app-', $ext, 4) === 0) { |
||
299 | $this->packageApplication(substr($ext, 4), $versions[$ext], $packagePath); |
||
300 | } else { |
||
301 | throw new Exception('Can not package extension.'); |
||
302 | } |
||
303 | } |
||
304 | |||
305 | $this->stdout("\ndone. verify the versions composer installed above and push it to github!\n\n"); |
||
306 | |||
307 | return 0; |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Sorts CHANGELOG for framework or extension. |
||
312 | * |
||
313 | * @param array $what what do you want to resort changelog for? this can either be: |
||
314 | * |
||
315 | * - an extension name such as `redis` or `bootstrap`, |
||
316 | * - or `framework` if you want to release a new version of the framework itself. |
||
317 | */ |
||
318 | public function actionSortChangelog(array $what) |
||
319 | { |
||
320 | if (\count($what) > 1) { |
||
321 | $this->stdout("Currently only one simultaneous release is supported.\n"); |
||
322 | return 1; |
||
323 | } |
||
324 | $this->validateWhat($what, ['framework', 'ext'], false); |
||
325 | |||
326 | $version = $this->version ?: array_values($this->getNextVersions($this->getCurrentVersions($what), self::PATCH))[0]; |
||
327 | $this->stdout('sorting CHANGELOG of '); |
||
328 | $this->stdout(reset($what), Console::BOLD); |
||
329 | $this->stdout(' for version '); |
||
330 | $this->stdout($version, Console::BOLD); |
||
331 | $this->stdout('...'); |
||
332 | |||
333 | $this->resortChangelogs($what, $version); |
||
334 | |||
335 | $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); |
||
336 | } |
||
337 | |||
338 | protected function printWhat(array $what, $newVersions, $versions) |
||
339 | { |
||
340 | foreach ($what as $ext) { |
||
341 | if (strncmp('app-', $ext, 4) === 0) { |
||
342 | $this->stdout(' - '); |
||
343 | $this->stdout(substr($ext, 4), Console::FG_RED); |
||
344 | $this->stdout(' application version '); |
||
345 | } elseif ($ext === 'framework') { |
||
346 | $this->stdout(' - Yii Framework version '); |
||
347 | } else { |
||
348 | $this->stdout(' - '); |
||
349 | $this->stdout($ext, Console::FG_RED); |
||
350 | $this->stdout(' extension version '); |
||
351 | } |
||
352 | $this->stdout($newVersions[$ext], Console::BOLD); |
||
353 | $this->stdout(", last release was {$versions[$ext]}\n"); |
||
354 | } |
||
355 | } |
||
356 | |||
357 | protected function printWhatUrls(array $what, $oldVersions) |
||
358 | { |
||
359 | foreach ($what as $ext) { |
||
360 | if ($ext === 'framework') { |
||
361 | $this->stdout("framework: https://github.com/yiisoft/yii2-framework/compare/{$oldVersions[$ext]}...master\n"); |
||
362 | $this->stdout("app-basic: https://github.com/yiisoft/yii2-app-basic/compare/{$oldVersions[$ext]}...master\n"); |
||
363 | $this->stdout("app-advanced: https://github.com/yiisoft/yii2-app-advanced/compare/{$oldVersions[$ext]}...master\n"); |
||
364 | } else { |
||
365 | $this->stdout($ext, Console::FG_RED); |
||
366 | $this->stdout(": https://github.com/yiisoft/yii2-$ext/compare/{$oldVersions[$ext]}...master\n"); |
||
367 | } |
||
368 | } |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * @param array $what list of items |
||
373 | * @param array $limit list of things to allow, or empty to allow any, can be `app`, `framework`, `extension` |
||
374 | * @param bool $ensureGitClean |
||
375 | * @throws \yii\base\Exception |
||
376 | */ |
||
377 | protected function validateWhat(array $what, $limit = [], $ensureGitClean = true) |
||
378 | { |
||
379 | foreach ($what as $w) { |
||
380 | if (strncmp('app-', $w, 4) === 0) { |
||
381 | if (!empty($limit) && !\in_array('app', $limit)) { |
||
382 | throw new Exception('Only the following types are allowed: ' . implode(', ', $limit) . "\n"); |
||
383 | } |
||
384 | if (!is_dir($appPath = "{$this->basePath}/apps/" . substr($w, 4))) { |
||
385 | throw new Exception("Application path does not exist: \"{$appPath}\"\n"); |
||
386 | } |
||
387 | if ($ensureGitClean) { |
||
388 | $this->ensureGitClean($appPath); |
||
389 | } |
||
390 | } elseif ($w === 'framework') { |
||
391 | if (!empty($limit) && !\in_array('framework', $limit)) { |
||
392 | throw new Exception('Only the following types are allowed: ' . implode(', ', $limit) . "\n"); |
||
393 | } |
||
394 | if (!is_dir($fwPath = "{$this->basePath}/framework")) { |
||
395 | throw new Exception("Framework path does not exist: \"{$this->basePath}/framework\"\n"); |
||
396 | } |
||
397 | if ($ensureGitClean) { |
||
398 | $this->ensureGitClean($fwPath); |
||
399 | } |
||
400 | } else { |
||
401 | if (!empty($limit) && !\in_array('ext', $limit)) { |
||
402 | throw new Exception('Only the following types are allowed: ' . implode(', ', $limit) . "\n"); |
||
403 | } |
||
404 | if (!is_dir($extPath = "{$this->basePath}/extensions/$w")) { |
||
405 | throw new Exception("Extension path for \"$w\" does not exist: \"{$this->basePath}/extensions/$w\"\n"); |
||
406 | } |
||
407 | if ($ensureGitClean) { |
||
408 | $this->ensureGitClean($extPath); |
||
409 | } |
||
410 | } |
||
411 | } |
||
412 | } |
||
413 | |||
414 | |||
415 | protected function releaseFramework($frameworkPath, $version) |
||
416 | { |
||
417 | $this->stdout("\n"); |
||
418 | $this->stdout($h = "Preparing framework release version $version", Console::BOLD); |
||
419 | $this->stdout("\n" . str_repeat('-', \strlen($h)) . "\n\n", Console::BOLD); |
||
420 | |||
421 | if (!$this->confirm('Make sure you are on the right branch for this release and that it tracks the correct remote branch! Continue?')) { |
||
0 ignored issues
–
show
The expression
$this->confirm('Make sur...ote branch! Continue?') of type boolean|null is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
422 | exit(1); |
||
423 | } |
||
424 | $this->runGit('git pull', $frameworkPath); |
||
425 | |||
426 | // checks |
||
427 | |||
428 | $this->stdout('check if framework composer.json matches yii2-dev composer.json...'); |
||
429 | $this->checkComposer($frameworkPath); |
||
430 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
431 | |||
432 | // adjustments |
||
433 | |||
434 | $this->stdout('prepare classmap...', Console::BOLD); |
||
435 | $this->dryRun || Yii::$app->runAction('classmap', [$frameworkPath]); |
||
436 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
437 | |||
438 | $this->stdout('updating mimetype magic file and mime aliases...', Console::BOLD); |
||
439 | $this->dryRun || Yii::$app->runAction('mime-type', ["$frameworkPath/helpers/mimeTypes.php"], ["$frameworkPath/helpers/mimeAliases.php"]); |
||
0 ignored issues
–
show
The call to
Application::runAction() has too many arguments starting with array("{$frameworkPath}/helpers/mimeAliases.php") .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the ![]() |
|||
440 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
441 | |||
442 | $this->stdout("fixing various PHPDoc style issues...\n", Console::BOLD); |
||
443 | $this->dryRun || Yii::$app->runAction('php-doc/fix', [$frameworkPath]); |
||
444 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
445 | |||
446 | $this->stdout("updating PHPDoc @property annotations...\n", Console::BOLD); |
||
447 | $this->dryRun || Yii::$app->runAction('php-doc/property', [$frameworkPath]); |
||
448 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
449 | |||
450 | $this->stdout('sorting changelogs...', Console::BOLD); |
||
451 | $this->dryRun || $this->resortChangelogs(['framework'], $version); |
||
452 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
453 | |||
454 | $this->stdout('closing changelogs...', Console::BOLD); |
||
455 | $this->dryRun || $this->closeChangelogs(['framework'], $version); |
||
456 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
457 | |||
458 | $this->stdout('updating Yii version...'); |
||
459 | $this->dryRun || $this->updateYiiVersion($frameworkPath, $version); |
||
460 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
461 | |||
462 | $this->stdout("\nIn the following you can check the above changes using git diff.\n\n"); |
||
463 | do { |
||
464 | $this->runGit('git diff --color', $frameworkPath); |
||
465 | $this->stdout("\n\n\nCheck whether the above diff is okay, if not you may change things as needed before continuing.\n"); |
||
466 | $this->stdout("You may abort the program with Ctrl + C and reset the changes by running `git checkout -- .` in the repo.\n\n"); |
||
467 | } while (!$this->confirm('Type `yes` to continue, `no` to view git diff again. Continue?')); |
||
468 | |||
469 | $this->stdout("\n\n"); |
||
470 | $this->stdout(" **** RELEASE TIME! ****\n", Console::FG_YELLOW, Console::BOLD); |
||
471 | $this->stdout(" **** Commit, Tag and Push it! ****\n", Console::FG_YELLOW, Console::BOLD); |
||
472 | $this->stdout("\n\nHint: if you decide 'no' for any of the following, the command will not be executed. You may manually run them later if needed. E.g. try the release locally without pushing it.\n\n"); |
||
473 | |||
474 | $this->stdout("Make sure to have your git set up for GPG signing. The following tag and commit should be signed.\n\n"); |
||
475 | |||
476 | $this->runGit("git commit -S -a -m \"release version $version\"", $frameworkPath); |
||
477 | $this->runGit("git tag -s $version -m \"version $version\"", $frameworkPath); |
||
478 | $this->runGit('git push', $frameworkPath); |
||
479 | $this->runGit('git push --tags', $frameworkPath); |
||
480 | |||
481 | $this->stdout("\n\n"); |
||
482 | $this->stdout('CONGRATULATIONS! You have just released ', Console::FG_YELLOW, Console::BOLD); |
||
483 | $this->stdout('framework', Console::FG_RED, Console::BOLD); |
||
484 | $this->stdout(' version ', Console::FG_YELLOW, Console::BOLD); |
||
485 | $this->stdout($version, Console::BOLD); |
||
486 | $this->stdout("!\n\n", Console::FG_YELLOW, Console::BOLD); |
||
487 | |||
488 | // TODO release applications |
||
489 | // $this->composerSetStability($what, $version); |
||
490 | |||
491 | |||
492 | // $this->resortChangelogs($what, $version); |
||
493 | // $this->closeChangelogs($what, $version); |
||
494 | // $this->composerSetStability($what, $version); |
||
495 | // if (in_array('framework', $what)) { |
||
496 | // $this->updateYiiVersion($version); |
||
497 | // } |
||
498 | |||
499 | |||
500 | // if done: |
||
501 | // * ./build/build release/done framework 2.0.0-dev 2.0.0-rc |
||
502 | // * ./build/build release/done redis 2.0.0-dev 2.0.0-rc |
||
503 | // $this->openChangelogs($what, $nextVersion); |
||
504 | // $this->composerSetStability($what, 'dev'); |
||
505 | // if (in_array('framework', $what)) { |
||
506 | // $this->updateYiiVersion($devVersion); |
||
507 | // } |
||
508 | |||
509 | |||
510 | |||
511 | // prepare next release |
||
512 | |||
513 | $this->stdout("Time to prepare the next release...\n\n", Console::FG_YELLOW, Console::BOLD); |
||
514 | |||
515 | $this->stdout('opening changelogs...', Console::BOLD); |
||
516 | $nextVersion = $this->getNextVersions(['framework' => $version], self::PATCH); // TODO support other versions |
||
517 | $this->dryRun || $this->openChangelogs(['framework'], $nextVersion['framework']); |
||
518 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
519 | |||
520 | $this->stdout('updating Yii version...'); |
||
521 | $this->dryRun || $this->updateYiiVersion($frameworkPath, $nextVersion['framework'] . '-dev'); |
||
522 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
523 | |||
524 | |||
525 | $this->stdout("\n"); |
||
526 | $this->runGit('git diff --color', $frameworkPath); |
||
527 | $this->stdout("\n\n"); |
||
528 | $this->runGit('git commit -a -m "prepare for next release"', $frameworkPath); |
||
529 | $this->runGit('git push', $frameworkPath); |
||
530 | |||
531 | $this->stdout("\n\nDONE!", Console::FG_YELLOW, Console::BOLD); |
||
532 | |||
533 | $this->stdout("\n\nThe following steps are left for you to do manually:\n\n"); |
||
534 | $nextVersion2 = $this->getNextVersions($nextVersion, self::PATCH); // TODO support other versions |
||
535 | $this->stdout("- wait for your changes to be propagated to the repo and create a tag $version on https://github.com/yiisoft/yii2-framework\n\n"); |
||
536 | $this->stdout(" git clone [email protected]:yiisoft/yii2-framework.git\n"); |
||
537 | $this->stdout(" cd yii2-framework/\n"); |
||
538 | $this->stdout(" export RELEASECOMMIT=$(git log --oneline |grep $version |grep -Po \"^[0-9a-f]+\")\n"); |
||
539 | $this->stdout(" git tag -s $version -m \"version $version\" \$RELEASECOMMIT\n"); |
||
540 | $this->stdout(" git tag --verify $version\n"); |
||
541 | $this->stdout(" git push --tags\n\n"); |
||
542 | $this->stdout("- close the $version milestone on github and open new ones for {$nextVersion['framework']} and {$nextVersion2['framework']}: https://github.com/yiisoft/yii2/milestones\n"); |
||
543 | $this->stdout("- create a release on github.\n"); |
||
544 | $this->stdout("- release news and announcement.\n"); |
||
545 | $this->stdout("- update the website (will be automated soon and is only relevant for the new website).\n"); |
||
546 | $this->stdout("\n"); |
||
547 | $this->stdout("- release applications: ./build/build release app-basic\n"); |
||
548 | $this->stdout("- release applications: ./build/build release app-advanced\n"); |
||
549 | |||
550 | $this->stdout("\n"); |
||
551 | } |
||
552 | |||
553 | protected function releaseApplication($name, $path, $version) |
||
554 | { |
||
555 | $this->stdout("\n"); |
||
556 | $this->stdout($h = "Preparing release for application $name version $version", Console::BOLD); |
||
557 | $this->stdout("\n" . str_repeat('-', \strlen($h)) . "\n\n", Console::BOLD); |
||
558 | |||
559 | if (!$this->confirm('Make sure you are on the right branch for this release and that it tracks the correct remote branch! Continue?')) { |
||
0 ignored issues
–
show
The expression
$this->confirm('Make sur...ote branch! Continue?') of type boolean|null is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
560 | exit(1); |
||
561 | } |
||
562 | $this->runGit('git pull', $path); |
||
563 | |||
564 | // adjustments |
||
565 | |||
566 | $this->stdout("fixing various PHPDoc style issues...\n", Console::BOLD); |
||
567 | $this->setAppAliases($name, $path); |
||
568 | $this->dryRun || Yii::$app->runAction('php-doc/fix', [$path, 'skipFrameworkRequirements' => true]); |
||
569 | $this->resetAppAliases(); |
||
570 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
571 | |||
572 | $this->stdout("updating PHPDoc @property annotations...\n", Console::BOLD); |
||
573 | $this->setAppAliases($name, $path); |
||
574 | $this->dryRun || Yii::$app->runAction('php-doc/property', [$path, 'skipFrameworkRequirements' => true]); |
||
575 | $this->resetAppAliases(); |
||
576 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
577 | |||
578 | $this->stdout("updating composer stability...\n", Console::BOLD); |
||
579 | $this->dryRun || $this->composerSetStability(["app-$name"], $version); |
||
580 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
581 | |||
582 | $this->stdout("\nIn the following you can check the above changes using git diff.\n\n"); |
||
583 | do { |
||
584 | $this->runGit('git diff --color', $path); |
||
585 | $this->stdout("\n\n\nCheck whether the above diff is okay, if not you may change things as needed before continuing.\n"); |
||
586 | $this->stdout("You may abort the program with Ctrl + C and reset the changes by running `git checkout -- .` in the repo.\n\n"); |
||
587 | } while (!$this->confirm('Type `yes` to continue, `no` to view git diff again. Continue?')); |
||
588 | |||
589 | $this->stdout("\n\n"); |
||
590 | $this->stdout(" **** RELEASE TIME! ****\n", Console::FG_YELLOW, Console::BOLD); |
||
591 | $this->stdout(" **** Commit, Tag and Push it! ****\n", Console::FG_YELLOW, Console::BOLD); |
||
592 | $this->stdout("\n\nHint: if you decide 'no' for any of the following, the command will not be executed. You may manually run them later if needed. E.g. try the release locally without pushing it.\n\n"); |
||
593 | |||
594 | $this->stdout("Make sure to have your git set up for GPG signing. The following tag and commit should be signed.\n\n"); |
||
595 | |||
596 | $this->runGit("git commit -S -a -m \"release version $version\"", $path); |
||
597 | $this->runGit("git tag -s $version -m \"version $version\"", $path); |
||
598 | $this->runGit('git push', $path); |
||
599 | $this->runGit('git push --tags', $path); |
||
600 | |||
601 | $this->stdout("\n\n"); |
||
602 | $this->stdout('CONGRATULATIONS! You have just released application ', Console::FG_YELLOW, Console::BOLD); |
||
603 | $this->stdout($name, Console::FG_RED, Console::BOLD); |
||
604 | $this->stdout(' version ', Console::FG_YELLOW, Console::BOLD); |
||
605 | $this->stdout($version, Console::BOLD); |
||
606 | $this->stdout("!\n\n", Console::FG_YELLOW, Console::BOLD); |
||
607 | |||
608 | // prepare next release |
||
609 | |||
610 | $this->stdout("Time to prepare the next release...\n\n", Console::FG_YELLOW, Console::BOLD); |
||
611 | |||
612 | $this->stdout("updating composer stability...\n", Console::BOLD); |
||
613 | $this->dryRun || $this->composerSetStability(["app-$name"], 'dev'); |
||
614 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
615 | |||
616 | $nextVersion = $this->getNextVersions(["app-$name" => $version], self::PATCH); // TODO support other versions |
||
617 | |||
618 | $this->stdout("\n"); |
||
619 | $this->runGit('git diff --color', $path); |
||
620 | $this->stdout("\n\n"); |
||
621 | $this->runGit('git commit -a -m "prepare for next release"', $path); |
||
622 | $this->runGit('git push', $path); |
||
623 | |||
624 | $this->stdout("\n\nDONE!", Console::FG_YELLOW, Console::BOLD); |
||
625 | |||
626 | $this->stdout("\n\nThe following steps are left for you to do manually:\n\n"); |
||
627 | $nextVersion2 = $this->getNextVersions($nextVersion, self::PATCH); // TODO support other versions |
||
628 | $this->stdout("- close the $version milestone on github and open new ones for {$nextVersion["app-$name"]} and {$nextVersion2["app-$name"]}: https://github.com/yiisoft/yii2-app-$name/milestones\n"); |
||
629 | $this->stdout("- Create Application packages and upload them to github: ./build release/package app-$name\n"); |
||
630 | |||
631 | $this->stdout("\n"); |
||
632 | } |
||
633 | |||
634 | private $_oldAlias; |
||
635 | |||
636 | protected function setAppAliases($app, $path) |
||
637 | { |
||
638 | $this->_oldAlias = Yii::getAlias('@app'); |
||
639 | switch ($app) { |
||
640 | case 'basic': |
||
641 | Yii::setAlias('@app', $path); |
||
642 | break; |
||
643 | case 'advanced': |
||
644 | // setup @frontend, @backend etc... |
||
645 | require "$path/common/config/bootstrap.php"; |
||
646 | break; |
||
647 | } |
||
648 | } |
||
649 | |||
650 | protected function resetAppAliases() |
||
651 | { |
||
652 | Yii::setAlias('@app', $this->_oldAlias); |
||
653 | } |
||
654 | |||
655 | protected function packageApplication($name, $version, $packagePath) |
||
656 | { |
||
657 | FileHelper::createDirectory($packagePath); |
||
658 | |||
659 | $this->runCommand("composer create-project yiisoft/yii2-app-$name $name $version", $packagePath); |
||
660 | // clear cookie validation key in basic app |
||
661 | if (is_file($configFile = "$packagePath/$name/config/web.php")) { |
||
662 | $this->sed( |
||
663 | "/'cookieValidationKey' => '.*?',/", |
||
664 | "'cookieValidationKey' => '',", |
||
665 | $configFile |
||
666 | ); |
||
667 | } |
||
668 | $this->runCommand("tar zcf yii-$name-app-$version.tgz $name", $packagePath); |
||
669 | } |
||
670 | |||
671 | protected function releaseExtension($name, $path, $version) |
||
672 | { |
||
673 | $this->stdout("\n"); |
||
674 | $this->stdout($h = "Preparing release for extension $name version $version", Console::BOLD); |
||
675 | $this->stdout("\n" . str_repeat('-', \strlen($h)) . "\n\n", Console::BOLD); |
||
676 | |||
677 | if (!$this->confirm('Make sure you are on the right branch for this release and that it tracks the correct remote branch! Continue?')) { |
||
0 ignored issues
–
show
The expression
$this->confirm('Make sur...ote branch! Continue?') of type boolean|null is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
678 | exit(1); |
||
679 | } |
||
680 | $this->runGit('git pull', $path); |
||
681 | |||
682 | // adjustments |
||
683 | |||
684 | $this->stdout("fixing various PHPDoc style issues...\n", Console::BOLD); |
||
685 | $this->dryRun || Yii::$app->runAction('php-doc/fix', [$path]); |
||
686 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
687 | |||
688 | $this->stdout("updating PHPDoc @property annotations...\n", Console::BOLD); |
||
689 | $this->dryRun || Yii::$app->runAction('php-doc/property', [$path]); |
||
690 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
691 | |||
692 | $this->stdout('sorting changelogs...', Console::BOLD); |
||
693 | $this->dryRun || $this->resortChangelogs([$name], $version); |
||
694 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
695 | |||
696 | $this->stdout('closing changelogs...', Console::BOLD); |
||
697 | $this->dryRun || $this->closeChangelogs([$name], $version); |
||
698 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
699 | |||
700 | $this->stdout("\nIn the following you can check the above changes using git diff.\n\n"); |
||
701 | do { |
||
702 | $this->runGit('git diff --color', $path); |
||
703 | $this->stdout("\n\n\nCheck whether the above diff is okay, if not you may change things as needed before continuing.\n"); |
||
704 | $this->stdout("You may abort the program with Ctrl + C and reset the changes by running `git checkout -- .` in the repo.\n\n"); |
||
705 | } while (!$this->confirm('Type `yes` to continue, `no` to view git diff again. Continue?')); |
||
706 | |||
707 | $this->stdout("\n\n"); |
||
708 | $this->stdout(" **** RELEASE TIME! ****\n", Console::FG_YELLOW, Console::BOLD); |
||
709 | $this->stdout(" **** Commit, Tag and Push it! ****\n", Console::FG_YELLOW, Console::BOLD); |
||
710 | $this->stdout("\n\nHint: if you decide 'no' for any of the following, the command will not be executed. You may manually run them later if needed. E.g. try the release locally without pushing it.\n\n"); |
||
711 | |||
712 | $this->stdout("Make sure to have your git set up for GPG signing. The following tag and commit should be signed.\n\n"); |
||
713 | |||
714 | $this->runGit("git commit -S -a -m \"release version $version\"", $path); |
||
715 | $this->runGit("git tag -s $version -m \"version $version\"", $path); |
||
716 | $this->runGit('git push', $path); |
||
717 | $this->runGit('git push --tags', $path); |
||
718 | |||
719 | $this->stdout("\n\n"); |
||
720 | $this->stdout('CONGRATULATIONS! You have just released extension ', Console::FG_YELLOW, Console::BOLD); |
||
721 | $this->stdout($name, Console::FG_RED, Console::BOLD); |
||
722 | $this->stdout(' version ', Console::FG_YELLOW, Console::BOLD); |
||
723 | $this->stdout($version, Console::BOLD); |
||
724 | $this->stdout("!\n\n", Console::FG_YELLOW, Console::BOLD); |
||
725 | |||
726 | // prepare next release |
||
727 | |||
728 | $this->stdout("Time to prepare the next release...\n\n", Console::FG_YELLOW, Console::BOLD); |
||
729 | |||
730 | $this->stdout('opening changelogs...', Console::BOLD); |
||
731 | $nextVersion = $this->getNextVersions([$name => $version], self::PATCH); // TODO support other versions |
||
732 | $this->dryRun || $this->openChangelogs([$name], $nextVersion[$name]); |
||
733 | $this->stdout("done.\n", Console::FG_GREEN, Console::BOLD); |
||
734 | |||
735 | $this->stdout("\n"); |
||
736 | $this->runGit('git diff --color', $path); |
||
737 | $this->stdout("\n\n"); |
||
738 | $this->runGit('git commit -a -m "prepare for next release"', $path); |
||
739 | $this->runGit('git push', $path); |
||
740 | |||
741 | $this->stdout("\n\nDONE!", Console::FG_YELLOW, Console::BOLD); |
||
742 | |||
743 | $this->stdout("\n\nThe following steps are left for you to do manually:\n\n"); |
||
744 | $nextVersion2 = $this->getNextVersions($nextVersion, self::PATCH); // TODO support other versions |
||
745 | $this->stdout("- close the $version milestone on github and open new ones for {$nextVersion[$name]} and {$nextVersion2[$name]}: https://github.com/yiisoft/yii2-$name/milestones\n"); |
||
746 | $this->stdout("- release news and announcement.\n"); |
||
747 | $this->stdout("- update the website (will be automated soon and is only relevant for the new website).\n"); |
||
748 | |||
749 | $this->stdout("\n"); |
||
750 | } |
||
751 | |||
752 | |||
753 | protected function runCommand($cmd, $path) |
||
754 | { |
||
755 | $this->stdout("running $cmd ...", Console::BOLD); |
||
756 | if ($this->dryRun) { |
||
757 | $this->stdout("dry run, command `$cmd` not executed.\n"); |
||
758 | return; |
||
759 | } |
||
760 | chdir($path); |
||
761 | exec($cmd, $output, $ret); |
||
762 | if ($ret != 0) { |
||
0 ignored issues
–
show
|
|||
763 | echo implode("\n", $output); |
||
764 | throw new Exception("Command \"$cmd\" failed with code " . $ret); |
||
765 | } |
||
766 | $this->stdout("\ndone.\n", Console::BOLD, Console::FG_GREEN); |
||
767 | } |
||
768 | |||
769 | protected function runGit($cmd, $path) |
||
770 | { |
||
771 | if ($this->confirm("Run `$cmd`?", true)) { |
||
772 | if ($this->dryRun) { |
||
773 | $this->stdout("dry run, command `$cmd` not executed.\n"); |
||
774 | return; |
||
775 | } |
||
776 | chdir($path); |
||
777 | exec($cmd, $output, $ret); |
||
778 | echo implode("\n", $output); |
||
779 | if ($ret != 0) { |
||
0 ignored issues
–
show
|
|||
780 | throw new Exception("Command \"$cmd\" failed with code " . $ret); |
||
781 | } |
||
782 | echo "\n"; |
||
783 | } |
||
784 | } |
||
785 | |||
786 | protected function ensureGitClean($path) |
||
787 | { |
||
788 | chdir($path); |
||
789 | exec('git status --porcelain -uno', $changes, $ret); |
||
790 | if ($ret != 0) { |
||
0 ignored issues
–
show
|
|||
791 | throw new Exception('Command "git status --porcelain -uno" failed with code ' . $ret); |
||
792 | } |
||
793 | if (!empty($changes)) { |
||
794 | throw new Exception("You have uncommitted changes in $path: " . print_r($changes, true)); |
||
795 | } |
||
796 | } |
||
797 | |||
798 | protected function gitFetchTags($path) |
||
799 | { |
||
800 | try { |
||
801 | chdir($path); |
||
802 | } catch (\yii\base\ErrorException $e) { |
||
803 | throw new Exception('Failed to getch git tags in ' . $path . ': ' . $e->getMessage()); |
||
804 | } |
||
805 | exec('git fetch --tags', $output, $ret); |
||
806 | if ($ret != 0) { |
||
0 ignored issues
–
show
|
|||
807 | throw new Exception('Command "git fetch --tags" failed with code ' . $ret); |
||
808 | } |
||
809 | } |
||
810 | |||
811 | |||
812 | protected function checkComposer($fwPath) |
||
0 ignored issues
–
show
|
|||
813 | { |
||
814 | if (!$this->confirm("\nNot yet automated: Please check if composer.json dependencies in framework dir match the one in repo root. Continue?", false)) { |
||
0 ignored issues
–
show
The expression
$this->confirm(' Not yet...oot. Continue?', false) of type boolean|null is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
815 | exit; |
||
816 | } |
||
817 | } |
||
818 | |||
819 | |||
820 | protected function closeChangelogs($what, $version) |
||
821 | { |
||
822 | $v = str_replace('\\-', '[\\- ]', preg_quote($version, '/')); |
||
823 | $headline = $version . ' ' . date('F d, Y'); |
||
824 | $this->sed( |
||
825 | '/' . $v . ' under development\R(-+?)\R/', |
||
826 | $headline . "\n" . str_repeat('-', \strlen($headline)) . "\n", |
||
827 | $this->getChangelogs($what) |
||
828 | ); |
||
829 | } |
||
830 | |||
831 | protected function openChangelogs($what, $version) |
||
832 | { |
||
833 | $headline = "\n$version under development\n"; |
||
834 | $headline .= str_repeat('-', \strlen($headline) - 2) . "\n\n- no changes in this release.\n"; |
||
835 | foreach ($this->getChangelogs($what) as $file) { |
||
836 | $lines = explode("\n", file_get_contents($file)); |
||
837 | $hl = [ |
||
838 | array_shift($lines), |
||
839 | array_shift($lines), |
||
840 | ]; |
||
841 | array_unshift($lines, $headline); |
||
842 | |||
843 | file_put_contents($file, implode("\n", array_merge($hl, $lines))); |
||
844 | } |
||
845 | } |
||
846 | |||
847 | protected function resortChangelogs($what, $version) |
||
848 | { |
||
849 | foreach ($this->getChangelogs($what) as $file) { |
||
850 | // split the file into relevant parts |
||
851 | list($start, $changelog, $end) = $this->splitChangelog($file, $version); |
||
852 | $changelog = $this->resortChangelog($changelog); |
||
853 | file_put_contents($file, implode("\n", array_merge($start, $changelog, $end))); |
||
854 | } |
||
855 | } |
||
856 | |||
857 | /** |
||
858 | * Extract changelog content for a specific version. |
||
859 | * @param string $file |
||
860 | * @param string $version |
||
861 | * @return array |
||
862 | */ |
||
863 | protected function splitChangelog($file, $version) |
||
864 | { |
||
865 | $lines = explode("\n", file_get_contents($file)); |
||
866 | |||
867 | // split the file into relevant parts |
||
868 | $start = []; |
||
869 | $changelog = []; |
||
870 | $end = []; |
||
871 | |||
872 | $state = 'start'; |
||
873 | foreach ($lines as $l => $line) { |
||
874 | // starting from the changelogs headline |
||
875 | if (isset($lines[$l - 2]) && strpos($lines[$l - 2], $version) !== false && |
||
876 | isset($lines[$l - 1]) && strncmp($lines[$l - 1], '---', 3) === 0) { |
||
877 | $state = 'changelog'; |
||
878 | } |
||
879 | if ($state === 'changelog' && isset($lines[$l + 1]) && strncmp($lines[$l + 1], '---', 3) === 0) { |
||
880 | $state = 'end'; |
||
881 | } |
||
882 | // add continued lines to the last item to keep them together |
||
883 | if (!empty(${$state}) && trim($line) !== '' && strncmp($line, '- ', 2) !== 0) { |
||
884 | end(${$state}); |
||
885 | ${$state}[key(${$state})] .= "\n" . $line; |
||
886 | } else { |
||
887 | ${$state}[] = $line; |
||
888 | } |
||
889 | } |
||
890 | |||
891 | return [$start, $changelog, $end]; |
||
892 | } |
||
893 | |||
894 | /** |
||
895 | * Ensure sorting of the changelog lines. |
||
896 | * @param string[] $changelog |
||
897 | * @return string[] |
||
898 | */ |
||
899 | protected function resortChangelog($changelog) |
||
900 | { |
||
901 | // cleanup whitespace |
||
902 | foreach ($changelog as $i => $line) { |
||
903 | $changelog[$i] = rtrim($line); |
||
904 | } |
||
905 | $changelog = array_filter($changelog); |
||
906 | |||
907 | $i = 0; |
||
908 | ArrayHelper::multisort($changelog, function ($line) use (&$i) { |
||
909 | if (preg_match('/^- (Chg|Enh|Bug|New)( #\d+(, #\d+)*)?: .+/', $line, $m)) { |
||
910 | $o = ['Bug' => 'C', 'Enh' => 'D', 'Chg' => 'E', 'New' => 'F']; |
||
911 | return $o[$m[1]] . ' ' . (!empty($m[2]) ? $m[2] : 'AAAA' . $i++); |
||
912 | } |
||
913 | |||
914 | return 'B' . $i++; |
||
915 | }, SORT_ASC, SORT_NATURAL); |
||
916 | |||
917 | // re-add leading and trailing lines |
||
918 | array_unshift($changelog, ''); |
||
919 | $changelog[] = ''; |
||
920 | $changelog[] = ''; |
||
921 | |||
922 | return $changelog; |
||
923 | } |
||
924 | |||
925 | protected function getChangelogs($what) |
||
926 | { |
||
927 | $changelogs = []; |
||
928 | if (\in_array('framework', $what)) { |
||
929 | $changelogs[] = $this->getFrameworkChangelog(); |
||
930 | } |
||
931 | |||
932 | return array_merge($changelogs, $this->getExtensionChangelogs($what)); |
||
933 | } |
||
934 | |||
935 | protected function getFrameworkChangelog() |
||
936 | { |
||
937 | return $this->basePath . '/framework/CHANGELOG.md'; |
||
938 | } |
||
939 | |||
940 | protected function getExtensionChangelogs($what) |
||
941 | { |
||
942 | return array_filter(glob($this->basePath . '/extensions/*/CHANGELOG.md'), function ($elem) use ($what) { |
||
943 | foreach ($what as $ext) { |
||
944 | if (strpos($elem, "extensions/$ext/CHANGELOG.md") !== false) { |
||
945 | return true; |
||
946 | } |
||
947 | } |
||
948 | |||
949 | return false; |
||
950 | }); |
||
951 | } |
||
952 | |||
953 | protected function composerSetStability($what, $version) |
||
954 | { |
||
955 | $apps = []; |
||
956 | if (\in_array('app-advanced', $what)) { |
||
957 | $apps[] = $this->basePath . '/apps/advanced/composer.json'; |
||
958 | } |
||
959 | if (\in_array('app-basic', $what)) { |
||
960 | $apps[] = $this->basePath . '/apps/basic/composer.json'; |
||
961 | } |
||
962 | if (\in_array('app-benchmark', $what)) { |
||
963 | $apps[] = $this->basePath . '/apps/benchmark/composer.json'; |
||
964 | } |
||
965 | if (empty($apps)) { |
||
966 | return; |
||
967 | } |
||
968 | |||
969 | $stability = 'stable'; |
||
970 | if (strpos($version, 'alpha') !== false) { |
||
971 | $stability = 'alpha'; |
||
972 | } elseif (strpos($version, 'beta') !== false) { |
||
973 | $stability = 'beta'; |
||
974 | } elseif (strpos($version, 'rc') !== false) { |
||
975 | $stability = 'RC'; |
||
976 | } elseif (strpos($version, 'dev') !== false) { |
||
977 | $stability = 'dev'; |
||
978 | } |
||
979 | |||
980 | $this->sed( |
||
981 | '/"minimum-stability": "(.+?)",/', |
||
982 | '"minimum-stability": "' . $stability . '",', |
||
983 | $apps |
||
984 | ); |
||
985 | } |
||
986 | |||
987 | protected function updateYiiVersion($frameworkPath, $version) |
||
988 | { |
||
989 | $this->sed( |
||
990 | '/function getVersion\(\)\R \{\R return \'(.+?)\';/', |
||
991 | "function getVersion()\n {\n return '$version';", |
||
992 | $frameworkPath . '/BaseYii.php'); |
||
993 | } |
||
994 | |||
995 | protected function sed($pattern, $replace, $files) |
||
996 | { |
||
997 | foreach ((array) $files as $file) { |
||
998 | file_put_contents($file, preg_replace($pattern, $replace, file_get_contents($file))); |
||
999 | } |
||
1000 | } |
||
1001 | |||
1002 | protected function getCurrentVersions(array $what) |
||
1003 | { |
||
1004 | $versions = []; |
||
1005 | foreach ($what as $ext) { |
||
1006 | if ($ext === 'framework') { |
||
1007 | chdir("{$this->basePath}/framework"); |
||
1008 | } elseif (strncmp('app-', $ext, 4) === 0) { |
||
1009 | chdir("{$this->basePath}/apps/" . substr($ext, 4)); |
||
1010 | } else { |
||
1011 | chdir("{$this->basePath}/extensions/$ext"); |
||
1012 | } |
||
1013 | $tags = []; |
||
1014 | exec('git tag', $tags, $ret); |
||
1015 | if ($ret != 0) { |
||
0 ignored issues
–
show
|
|||
1016 | throw new Exception('Command "git tag" failed with code ' . $ret); |
||
1017 | } |
||
1018 | rsort($tags, SORT_NATURAL); // TODO this can not deal with alpha/beta/rc... |
||
1019 | $versions[$ext] = reset($tags); |
||
1020 | } |
||
1021 | |||
1022 | return $versions; |
||
1023 | } |
||
1024 | |||
1025 | const MINOR = 'minor'; |
||
1026 | const PATCH = 'patch'; |
||
1027 | |||
1028 | protected function getNextVersions(array $versions, $type) |
||
1029 | { |
||
1030 | foreach ($versions as $k => $v) { |
||
1031 | if (empty($v)) { |
||
1032 | $versions[$k] = '2.0.0'; |
||
1033 | continue; |
||
1034 | } |
||
1035 | $parts = explode('.', $v); |
||
1036 | switch ($type) { |
||
1037 | case self::MINOR: |
||
1038 | $parts[1]++; |
||
1039 | $parts[2] = 0; |
||
1040 | if (isset($parts[3])) { |
||
1041 | unset($parts[3]); |
||
1042 | } |
||
1043 | break; |
||
1044 | case self::PATCH: |
||
1045 | $parts[2]++; |
||
1046 | if (isset($parts[3])) { |
||
1047 | unset($parts[3]); |
||
1048 | } |
||
1049 | break; |
||
1050 | default: |
||
1051 | throw new Exception('Unknown version type.'); |
||
1052 | } |
||
1053 | $versions[$k] = implode('.', $parts); |
||
1054 | } |
||
1055 | |||
1056 | return $versions; |
||
1057 | } |
||
1058 | } |
||
1059 |
If an expression can have both
false
, andnull
as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.