Files
archived-ai/bump
2026-02-19 11:57:06 +01:00

193 lines
7.7 KiB
PHP
Executable File

#!/usr/bin/env php
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require __DIR__.'/vendor/autoload.php';
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
/**
* Bumps the version and updates version constraints for symfony/ai-* dependencies across the monorepo.
* Reads the current version from src/mate/src/App.php.
*
* For release, run this script with one of the following options:
* ./bump --major : Bump major version (X.0.0)
* ./bump --minor : Bump minor version (x.X.0)
* ./bump --patch : Bump patch version (x.x.X)
*
* This will also update all symfony/ai-* composer constraints to match the new version.
*
* Alternatively, you can specify an explicit version with:
* ./bump --release=1.2.3 : Set explicit release version
* ./bump --constraint="^1.2" : Set explicit composer constraint
*
* @author Christopher Hertel <mail@christopher-hertel.de>
*/
(new SingleCommandApplication())
->setName('Symfony AI Version Bump')
->setDescription('Bumps the version and updates version constraints for symfony/ai-* dependencies across the monorepo.')
->addOption('major', null, InputOption::VALUE_NONE, 'Bump major version (X.0.0)')
->addOption('minor', null, InputOption::VALUE_NONE, 'Bump minor version (x.X.0)')
->addOption('patch', null, InputOption::VALUE_NONE, 'Bump patch version (x.x.X)')
->addOption('release', null, InputOption::VALUE_REQUIRED, 'Set explicit release version (e.g., 1.2.3)')
->addOption('constraint', null, InputOption::VALUE_REQUIRED, 'Set explicit composer constraint (e.g., ^1.2)')
->setCode(function (InputInterface $input, OutputInterface $output): int {
$filesystem = new Filesystem();
$io = new SymfonyStyle($input, $output);
$isMajor = $input->getOption('major');
$isMinor = $input->getOption('minor');
$isPatch = $input->getOption('patch');
$releaseVersion = $input->getOption('release');
$composerConstraint = $input->getOption('constraint');
$bumpOptions = array_filter([
'major' => $isMajor,
'minor' => $isMinor,
'patch' => $isPatch,
'release' => $releaseVersion,
]);
if (1 !== \count($bumpOptions)) {
$io->error('You must specify exactly one of --major, --minor, --patch, or --release');
return Command::FAILURE;
}
$appPhpPath = __DIR__.'/src/mate/src/App.php';
$appPhpContent = $filesystem->readFile($appPhpPath);
if (!preg_match('/public const VERSION = \'([0-9]+\.[0-9]+\.[0-9]+)\';/', $appPhpContent, $matches)) {
$io->error('Could not find VERSION constant in App.php');
return Command::FAILURE;
}
$currentVersion = $matches[1];
[$major, $minor, $patch] = explode('.', $currentVersion);
$io->writeln(\sprintf('Current version: <info>%s</info>', $currentVersion));
// Calculate new version
if ($releaseVersion) {
$newVersion = $releaseVersion;
if (!preg_match('/^[0-9]+\.[0-9]+\.[0-9]+$/', $newVersion)) {
$io->error('Version must be in format X.Y.Z (e.g., 1.2.3)');
return Command::FAILURE;
}
[$newMajor, $newMinor, $newPatch] = explode('.', $newVersion);
} elseif ($isMajor) {
$newMajor = (int) $major + 1;
$newMinor = 0;
$newPatch = 0;
$newVersion = \sprintf('%s.%s.%s', $newMajor, $newMinor, $newPatch);
} elseif ($isMinor) {
$newMajor = (int) $major;
$newMinor = (int) $minor + 1;
$newPatch = 0;
$newVersion = \sprintf('%s.%s.%s', $newMajor, $newMinor, $newPatch);
} elseif ($isPatch) {
$newMajor = (int) $major;
$newMinor = (int) $minor;
$newPatch = (int) $patch + 1;
$newVersion = \sprintf('%s.%s.%s', $newMajor, $newMinor, $newPatch);
}
$io->writeln(\sprintf('New version: <info>%s</info>', $newVersion));
// Calculate composer constraint
if (!$composerConstraint) {
// For patch bumps, keep the current minor version constraint (^X.Y)
// For minor bumps, use the new minor version constraint (^X.Y)
// For major bumps, use the new major version constraint (^X.0)
if ($isPatch) {
$composerConstraint = \sprintf('^%s.%s', $newMajor, $newMinor);
} elseif ($isMinor || $isMajor) {
$composerConstraint = \sprintf('^%s.%s', $newMajor, $newMinor);
} elseif ($releaseVersion) {
// For explicit version, use ^X.Y
$composerConstraint = \sprintf('^%s.%s', $newMajor, $newMinor);
}
}
$io->writeln(\sprintf('Composer constraint: <info>%s</info>', $composerConstraint));
$io->newLine();
if (!$io->confirm('Proceed with these changes?')) {
$io->warning('Aborted by user.');
return Command::SUCCESS;
}
$newAppPhpContent = preg_replace(
'/public const VERSION = \'[0-9]+\.[0-9]+\.[0-9]+\';/',
\sprintf("public const VERSION = '%s';", $newVersion),
$appPhpContent
);
$filesystem->dumpFile($appPhpPath, $newAppPhpContent);
$io->writeln('<info>✓</info> Updated VERSION constant in App.php');
$totalUpdates = 0;
$finder = new Finder();
$finder->files()
->name('composer.json')
->in([__DIR__.'/src', __DIR__.'/demo', __DIR__.'/examples'])
->exclude('vendor');
$io->writeln(\sprintf('Found %d composer.json files to process:', $finder->count()));
foreach ($finder as $file) {
$composerFile = $file->getRealPath();
$content = $file->getContents();
$data = json_decode($content, true);
if (!$data) {
$io->writeln(\sprintf(' <comment>⚠</comment> Skipping "%s" (invalid JSON)', $file->getRelativePathname()));
continue;
}
$modified = false;
$fileUpdates = 0;
foreach (['require', 'require-dev'] as $section) {
foreach ($data[$section] ?? [] as $package => $constraint) {
if (str_starts_with($package, 'symfony/ai-') || 'symfony/mcp-bundle' === $package) {
$data[$section][$package] = $composerConstraint;
$modified = true;
++$fileUpdates;
}
}
}
// Write back if modified
if ($modified) {
$newContent = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)."\n";
$filesystem->dumpFile($composerFile, $newContent);
$totalUpdates += $fileUpdates;
$io->writeln(\sprintf(' <info>✓</info> Saved "%s" with %d change(s)', str_replace(__DIR__.'/', '', $file->getRealPath()), $fileUpdates));
}
}
$io->newLine();
$io->success(\sprintf('Successfully bumped version to %s and updated %d dependency constraints in %d files to "%s".', $newVersion, $totalUpdates, $finder->count(), $composerConstraint));
return Command::SUCCESS;
})
->run();