feat: add a command to release Koel

This commit is contained in:
Phan An 2024-09-02 12:32:08 +02:00
parent 618929e9bf
commit 0b99f3a1f3
4 changed files with 219 additions and 38 deletions

View file

@ -0,0 +1,149 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Process;
use PHLAK\SemVer\Version;
use Throwable;
use function Laravel\Prompts\error;
use function Laravel\Prompts\info;
use function Laravel\Prompts\note;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
use function Laravel\Prompts\warning;
class ReleaseCommand extends Command
{
protected $signature
= 'koel:release {version? : The version to release, or "patch", "minor", "major" for auto-increment}';
protected $description = 'Tag and release a new version of Koel';
private Version $currentVersion;
public function handle(): int
{
self::ensureCleanWorkingDirectory();
$this->getCurrentVersion();
$releaseVersion = match ($this->argument('version')) {
'patch' => (clone $this->currentVersion)->incrementPatch()->prefix(),
'minor' => (clone $this->currentVersion)->incrementMinor()->prefix(),
'major' => (clone $this->currentVersion)->incrementMajor()->prefix(),
null => $this->acquireReleaseVersionInteractively(),
default => self::tryParseVersion($this->argument('version')) ?? $this->acquireReleaseVersionInteractively(),
};
try {
$this->release($releaseVersion);
} catch (Throwable $e) {
error($e->getMessage());
warning('Something went wrong. Double-check the working directory and maybe try again.');
return self::FAILURE;
}
return self::SUCCESS;
}
private function release(string $version): void
{
// Ensure the version is prefixed.
$version = Version::parse($version)->prefix();
info("Releasing version $version...");
File::put(base_path('.version'), $version);
$gitCommands = [
'add .',
"commit -m 'chore(release): bump version to $version'",
'push',
"tag $version",
'tag latest -f',
'push origin --tags -f',
'checkout release',
'pull',
'merge master',
'push',
];
foreach ($gitCommands as $command) {
$this->components->task("Executing `git $command`", static fn () => self::runOkOrThrow("git $command"));
}
info("Success! The new version $version has been tagged.");
info('Now go to https://github.com/koel/koel/releases and finish the draft release notes.');
}
private function acquireReleaseVersionInteractively(): string
{
$patchVersion = (clone $this->currentVersion)->incrementPatch()->prefix();
$suggestedVersions = [
$patchVersion => 'Patch',
(clone $this->currentVersion)->incrementMinor()->prefix() => 'Minor',
(clone $this->currentVersion)->incrementMajor()->prefix() => 'Major',
];
$options = [];
foreach ($suggestedVersions as $version => $name) {
$options[$version] = "$name -> $version";
}
$options['custom'] = 'Custom';
$selected = select(
label: 'What are we releasing?',
options: $options,
default: $patchVersion,
);
if ($selected === 'custom') {
$selected = text(
label: 'Enter the version you want to release',
placeholder: $patchVersion,
required: true,
validate: static fn (string $value) => self::tryParseVersion($value)
? null
: 'Invalid version format',
);
}
return Version::parse($selected)->prefix();
}
private static function tryParseVersion(string $version): ?string
{
try {
return Version::parse($version)->prefix();
} catch (Throwable) {
return null;
}
}
public function getCurrentVersion(): void
{
$this->currentVersion = new Version(File::get(base_path('.version')));
note('Current version: ' . $this->currentVersion->prefix());
}
private static function ensureCleanWorkingDirectory(): void
{
if (Process::run('git status --porcelain')->output()) {
error('Your working directly is not clean. Please commit or stash your changes before proceeding.');
exit(self::FAILURE);
}
}
private static function runOkOrThrow(string $command): void
{
throw_unless(Process::forever()->run($command)->successful());
}
}

View file

@ -55,7 +55,9 @@
"fakerphp/faker": "^1.13",
"slevomat/coding-standard": "^7.0",
"laravel/tinker": "^2.9",
"larastan/larastan": "^2.9"
"larastan/larastan": "^2.9",
"phlak/semver": "^5.0",
"laravel/prompts": "^0.1.25"
},
"suggest": {
"ext-zip": "Allow downloading multiple songs as Zip archives"

74
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "9da46e14c758c109ce78f30cbaa63a09",
"content-hash": "518f509cd591617642652600dccb90c6",
"packages": [
{
"name": "algolia/algoliasearch-client-php",
@ -2635,16 +2635,16 @@
},
{
"name": "laravel/prompts",
"version": "v0.1.19",
"version": "v0.1.25",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18"
"reference": "7b4029a84c37cb2725fc7f011586e2997040bc95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/0ab75ac3434d9f610c5691758a6146a3d1940c18",
"reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18",
"url": "https://api.github.com/repos/laravel/prompts/zipball/7b4029a84c37cb2725fc7f011586e2997040bc95",
"reference": "7b4029a84c37cb2725fc7f011586e2997040bc95",
"shasum": ""
},
"require": {
@ -2684,11 +2684,12 @@
"license": [
"MIT"
],
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.1.19"
"source": "https://github.com/laravel/prompts/tree/v0.1.25"
},
"time": "2024-04-16T14:20:35+00:00"
"time": "2024-08-12T22:06:33+00:00"
},
{
"name": "laravel/sanctum",
@ -10911,6 +10912,65 @@
},
"time": "2022-02-21T01:04:05+00:00"
},
{
"name": "phlak/semver",
"version": "5.0.0",
"source": {
"type": "git",
"url": "https://github.com/PHLAK/SemVer.git",
"reference": "3c4db3a7953ac414b947c183548b6a5b825da738"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHLAK/SemVer/zipball/3c4db3a7953ac414b947c183548b6a5b825da738",
"reference": "3c4db3a7953ac414b947c183548b6a5b825da738",
"shasum": ""
},
"require": {
"php": "^8.0 || ^8.1 || ^8.2 || 8.3"
},
"require-dev": {
"phlak/coding-standards": "^2.0",
"phpstan/phpstan": "^1.11",
"phpunit/phpunit": "^9.0 || ^10.0",
"yoast/phpunit-polyfills": "^2.0"
},
"type": "library",
"autoload": {
"files": [
"src/Support/helpers.php"
],
"psr-4": {
"PHLAK\\SemVer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Kankiewicz",
"email": "Chris@ChrisKankiewicz.com"
}
],
"description": "Semantic versioning helper library",
"support": {
"issues": "https://github.com/PHLAK/SemVer/issues",
"source": "https://github.com/PHLAK/SemVer/tree/5.0.0"
},
"funding": [
{
"url": "https://github.com/sponsors/PHLAK",
"type": "github"
},
{
"url": "https://paypal.me/ChrisKankiewicz",
"type": "paypal"
}
],
"time": "2024-08-02T16:57:17+00:00"
},
{
"name": "php-mock/php-mock",
"version": "2.5.0",

30
tag.sh
View file

@ -1,30 +0,0 @@
#!/usr/bin/env bash
if [[ $(git status --porcelain) ]]; then
echo 'ERROR: Please commit all changes before tagging a new version.'
exit 1
fi
if [ -z "$1" ]; then
echo 'ERROR: You must supply a version number.'
exit 1
fi
TAG=$1
echo "$TAG" > .version
git -c color.ui=always add .
git -c color.ui=always commit -m "chore(release): bump version to ${TAG}"
git -c color.ui=always push
git -c color.ui=always tag "$TAG"
git -c color.ui=always tag latest -f
git -c color.ui=always push --tags -f
# Update and push the release branch so that documentation is updated
echo "Update the release branch"
git -c color.ui=always checkout release
git -c color.ui=always pull
git -c color.ui=always merge master
git -c color.ui=always push
echo "${TAG} tagged. Now go to https://github.com/koel/koel/releases and finish the draft release."