Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ concurrency:
cancel-in-progress: true

jobs:

sniff:
runs-on: ubuntu-latest
name: Sniff
Expand Down Expand Up @@ -66,26 +65,21 @@ jobs:

strategy:
fail-fast: true
max-parallel: 2
max-parallel: 3
matrix:
php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
php: ["7.4", "8.0", "8.1", "8.2", "8.3", "8.4"]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup PHP for dependencies
- name: Setup PHP for test
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
php-version: ${{ matrix.php }}

- name: Install PHP dependencies
uses: ramsey/composer-install@v3

- name: Setup PHP for test
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}

- name: Run test
run: composer test
2 changes: 2 additions & 0 deletions app/Commander.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Syntatis\Version\CLI\Commands\IncrementCommand;
use Syntatis\Version\CLI\Commands\ValidateCommand;

final class Commander extends Application
Expand All @@ -26,6 +27,7 @@ public function __construct()
private function getCommands(): array
{
return [
new IncrementCommand(),
new ValidateCommand(),
];
}
Expand Down
122 changes: 122 additions & 0 deletions app/Commands/IncrementCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

declare(strict_types=1);

namespace Syntatis\Version\CLI\Commands;

use InvalidArgumentException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Syntatis\Version\CLI\Exceptions\InvalidArgumentType;
use Throwable;
use Version\Version;

use function is_string;
use function sprintf;

final class IncrementCommand extends Command
{
/**
* Configure the command options and arguments.
*/
protected function configure(): void
{
$this->setName('increment');
$this->setDescription('Increment a version.');
$this->setHelp('This command increments the provided version by the specified part (major, minor, patch).');
$this->setAliases(['incr', 'bump']);
$this->addArgument('version', InputArgument::REQUIRED, 'Version to increment');
$this->addOption('part', 'p', InputArgument::OPTIONAL, 'Part to increment (major, minor, patch)', 'patch');
$this->addOption('build', 'b', InputArgument::OPTIONAL, 'Build metadata to append to the version');
$this->addOption('pre', null, InputArgument::OPTIONAL, 'Pre-release identifier to append to the version');
$this->setHelp(<<<'HELP'
This command increments the provided version by the specified part (major, minor, patch).
You can also append build metadata or a pre-release identifier to the version.

Usage:
<info>version increment 1.0.0</info>
<info>version increment 1.0.0 --part=minor</info>
<info>version increment 1.0.0 --build=123</info>
<info>version increment 1.0.0 --pre=beta</info>
HELP,);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$style = new SymfonyStyle($input, $output);
$part = $input->getOption('part');
$version = $input->getArgument('version');
$build = $input->getOption('build');
$pre = $input->getOption('pre');

try {
if (! is_string($part)) {
throw new InvalidArgumentType($part);
}
} catch (Throwable $th) {
$style->error($th->getMessage());

return Command::FAILURE;
}

try {
if (! is_string($version)) {
throw new InvalidArgumentType($version);
}

/** @var Version $parsed */
$parsed = Version::fromString($version);
$style->writeln(
(string) $this->increment(
$parsed,
$part,
$pre,
$build,
),
);
} catch (Throwable $th) {
$style->error($th->getMessage());

return Command::FAILURE;
}

return Command::SUCCESS;
}

/**
* @param mixed $pre
* @param mixed $build
*/
private function increment(Version $version, string $part, $pre = null, $build = null): Version
{
switch ($part) {
case 'major':
$version = $version->incrementMajor();
break;

case 'minor':
$version = $version->incrementMinor();
break;

case 'patch':
$version = $version->incrementPatch();
break;

default:
throw new InvalidArgumentException(sprintf("Invalid part '%s' provided. Expected 'major', 'minor', or 'patch'.", $part));
}

if (is_string($pre) && $pre !== '') {
$version = $version->withPreRelease($pre);
}

if (is_string($build) && $build !== '') {
$version = $version->withBuild($build);
}

return $version;
}
}
6 changes: 3 additions & 3 deletions app/Commands/ValidateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Syntatis\Version\CLI\Exceptions\InvalidArgumentType;
use Throwable;
use TypeError;
use Version\Version;

use function gettype;
use function is_string;
use function sprintf;

Expand All @@ -39,12 +38,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
try {
if (is_string($version)) {
Version::fromString($version);

$style->success(sprintf("Version string '%s' is valid and can be parsed", $version));

return Command::SUCCESS;
}

throw new TypeError(sprintf("Invalid type of value to validate. Expected string, '%s' given", gettype($version)));
throw new InvalidArgumentType($version);
} catch (Throwable $th) {
$style->error($th->getMessage());

Expand Down
19 changes: 19 additions & 0 deletions app/Exceptions/InvalidArgumentType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Syntatis\Version\CLI\Exceptions;

use InvalidArgumentException;

use function gettype;
use function sprintf;

class InvalidArgumentType extends InvalidArgumentException
{
/** @param mixed $value */
public function __construct($value)
{
parent::__construct(sprintf("Invalid type of value. Expected '%s', '%s' given", 'string', gettype($value)));
}
}
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "syntatis/version-cli-php",
"description": "Increment, compare SemVer-compliant version number with CLI.",
"name": "syntatis/version-cli",
"description": "Validate, increment, and compare SemVer-compliant version number with CLI",
"keywords": ["version", "cli", "semver"],
"authors": [
{
Expand All @@ -20,8 +20,8 @@
},
"require": {
"php": "^7.4 || ^8.0",
"nikolaposa/version": "^4.1",
"symfony/console": "^5.4"
"nikolaposa/version": "^4.1.1",
"symfony/console": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
Expand Down
82 changes: 82 additions & 0 deletions tests/app/Commands/IncrementCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace Syntatis\Tests\Commands;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Syntatis\Version\CLI\Commander;

use function sprintf;

class IncrementCommandTest extends TestCase
{
private Commander $commander;

public function setUp(): void
{
parent::setUp();

$this->commander = new Commander();
}

/** @dataProvider dataInvalidVersionArgument */
public function testInvalidVersionArgument(string $version): void
{
$tester = new CommandTester($this->commander->get('increment'));
$tester->execute(['version' => $version]);

self::assertStringContainsString(
sprintf("[ERROR] Version string '%s' is not valid and cannot be parsed", $version),
$tester->getDisplay(),
);
}

public function testIncrementPatch(): void
{
$tester = new CommandTester($this->commander->get('increment'));
$tester->execute(['version' => '1.0.0']);

self::assertStringContainsString('1.0.1', $tester->getDisplay());
}

public function testIncrementMinor(): void
{
$tester = new CommandTester($this->commander->get('increment'));
$tester->execute(['version' => '1.0.0', '--part' => 'minor']);

self::assertStringContainsString('1.1.0', $tester->getDisplay());
}

public function testIncrementMajor(): void
{
$tester = new CommandTester($this->commander->get('increment'));
$tester->execute(['version' => '1.0.0', '--part' => 'major']);

self::assertStringContainsString('2.0.0', $tester->getDisplay());
}

public function testIncrementWithBuildMetadata(): void
{
$tester = new CommandTester($this->commander->get('increment'));
$tester->execute(['version' => '1.0.0', '--build' => '123']);

self::assertStringContainsString('1.0.1+123', $tester->getDisplay());
}

public function testIncrementWithPreRelease(): void
{
$tester = new CommandTester($this->commander->get('increment'));
$tester->execute(['version' => '1.0.0', '--pre' => 'beta']);

self::assertStringContainsString('1.0.1-beta', $tester->getDisplay());
}

public static function dataInvalidVersionArgument(): iterable
{
yield ['v'];
yield ['v0'];
yield ['v0.0'];
}
}