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()); } }