From f8b2eceb2317de294654aa3af1954219837a8757 Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Tue, 4 Jun 2024 10:37:56 +0200 Subject: [PATCH 1/6] Run CI --- .github/workflows/ci.yml | 9 ++++ .gitignore | 3 ++ composer.json | 35 +++++++++++--- phpstan.neon | 2 + src/Command/InitializeCommand.php | 5 +- src/Command/LegacyCommand.php | 63 -------------------------- src/Exception/InvalidCallException.php | 7 +++ src/Initializer/InitializeHelper.php | 27 ++++++++--- vendor-bin/c-norm/composer.json | 11 +++++ vendor-bin/cs-fixer/composer.json | 6 +++ vendor-bin/phpstan/composer.json | 21 +++++++++ 11 files changed, 110 insertions(+), 79 deletions(-) create mode 100644 phpstan.neon delete mode 100644 src/Command/LegacyCommand.php create mode 100644 src/Exception/InvalidCallException.php create mode 100644 vendor-bin/c-norm/composer.json create mode 100644 vendor-bin/cs-fixer/composer.json create mode 100644 vendor-bin/phpstan/composer.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 770a05a..a1a2cf8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,15 @@ jobs: php --version php -r 'foreach (get_loaded_extensions() as $extension) echo $extension . " " . phpversion($extension) . PHP_EOL;' + - name: Install Composer + run: composer install --optimize-autoloader --classmap-authoritative --no-interaction + + - name: Run Linters + run: composer run-script lint + + - name: Run Tests + run: composer run-script test + - name: "Install Composer: Library / Composer Normalize" run: composer install --optimize-autoloader --classmap-authoritative --no-interaction working-directory: _init/library/vendor-bin/c-norm diff --git a/.gitignore b/.gitignore index ff72e2d..b5adc56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ +/.php-cs-fixer.cache /composer.lock /vendor +/vendor-bin/*/composer.lock +/vendor-bin/*/vendor diff --git a/composer.json b/composer.json index be9086d..0919acf 100644 --- a/composer.json +++ b/composer.json @@ -1,15 +1,15 @@ { "name": "21torr/janus", - "type": "lib", "description": "Code style, encoded as rules for common tools.", - "homepage": "https://github.com/21TORR/janus-php", "license": "BSD-3-Clause", + "type": "lib", "authors": [ { "name": "21TORR", "homepage": "https://www.21torr.com/" } ], + "homepage": "https://github.com/21TORR/janus-php", "require": { "php": ">= 8.3", "21torr/cli": "^1.2", @@ -17,21 +17,42 @@ "symfony/process": "^7.0" }, "require-dev": { + "bamarni/composer-bin-plugin": "^1.8", "roave/security-advisories": "dev-latest" }, - "bin": [ - "bin/janus" - ], "autoload": { "psr-4": { "Janus\\": "src/" } }, + "bin": [ + "bin/janus" + ], "config": { - "sort-packages": true, "allow-plugins": { + "bamarni/composer-bin-plugin": true, "ergebnis/composer-normalize": true, "phpstan/extension-installer": true + }, + "sort-packages": true + }, + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": true } + }, + "scripts": { + "fix-lint": [ + "@composer bin c-norm normalize \"$(pwd)/composer.json\" --indent-style tab --indent-size 1 --ansi", + "vendor-bin/cs-fixer/vendor/bin/php-cs-fixer fix --diff --config vendor-bin/cs-fixer/vendor/21torr/php-cs-fixer/.php-cs-fixer.dist.php --no-interaction --ansi" + ], + "lint": [ + "@composer bin c-norm normalize \"$(pwd)/composer.json\" --indent-style tab --indent-size 1 --dry-run --ansi", + "vendor-bin/cs-fixer/vendor/bin/php-cs-fixer fix --diff --config vendor-bin/cs-fixer/vendor/21torr/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --no-interaction --ansi" + ], + "test": [ + "vendor-bin/phpstan/vendor/bin/phpstan analyze -c phpstan.neon . --ansi" + ] } -} +} \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..221849f --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,2 @@ +includes: + - phpstan/lib.neon diff --git a/src/Command/InitializeCommand.php b/src/Command/InitializeCommand.php index 49f84c1..eec9d68 100644 --- a/src/Command/InitializeCommand.php +++ b/src/Command/InitializeCommand.php @@ -22,7 +22,7 @@ public function __construct () /** * @inheritDoc */ - protected function configure () + protected function configure () : void { $this ->setDescription("Initializes a given command") @@ -30,6 +30,7 @@ protected function configure () "type", InputArgument::REQUIRED, "The project type to initialize", + default: null, suggestedValues: [ "symfony", "library", @@ -45,10 +46,10 @@ protected function execute (InputInterface $input, OutputInterface $output) : in $io = new TorrStyle($input, $output); $io->title("Janus: Initialize"); - try { $type = $input->getArgument("type"); + \assert(\is_string($type)); $initializer = match ($type) { diff --git a/src/Command/LegacyCommand.php b/src/Command/LegacyCommand.php deleted file mode 100644 index 6754579..0000000 --- a/src/Command/LegacyCommand.php +++ /dev/null @@ -1,63 +0,0 @@ -setDescription("Deprecated command to ") - ->setAliases(["init-library"]); - } - - /** - * @inheritDoc - */ - #[\Override] - protected function execute (InputInterface $input, OutputInterface $output) : int - { - $io = new TorrStyle($input, $output); - - $calledCommand = $input->getFirstArgument(); - - $io->caution("This command is deprecated"); - $io->comment(\sprintf( - "The command %s is deprecated, use %s instead.", - $calledCommand, - \strtr($calledCommand, ["-" => " "]), - )); - - $fakedInput = new ArrayInput([ - "command" => "init", - "type" => match ($calledCommand) - { - "init-symfony" => "symfony", - "init-library" => "library", - default => \assert(false), - }, - ]); - $application = $this->getApplication(); - \assert(null !== $application); - - return $application->run($fakedInput, $output); - } -} diff --git a/src/Exception/InvalidCallException.php b/src/Exception/InvalidCallException.php new file mode 100644 index 0000000..48fac36 --- /dev/null +++ b/src/Exception/InvalidCallException.php @@ -0,0 +1,7 @@ +cwd = \getcwd(); + $this->cwd = (string) \getcwd(); } /** @@ -39,6 +39,8 @@ public function copyFilesIntoProject (string $directory) : void /** * Add the given config to the projects composer.json + * + * @param array $config */ public function addToProjectComposerJson (array $config) : void { @@ -58,13 +60,14 @@ public function addToProjectComposerJson (array $config) : void * If there are multiple lines matching, all will be replaced. * If there are no lines matching, the call will just be appended. * - * - * @param string $key The scripts key to update. + * @param string $key The scripts key to update. * @param array $scripts The scripts to replace. */ - function updateProjectComposerJsonScripts (string $key, array $scripts) : void + public function updateProjectComposerJsonScripts (string $key, array $scripts) : void { $jsonContent = $this->readProjectComposerJson(); + \assert(!isset($jsonContent["scripts"]) || \is_array($jsonContent["scripts"])); + $existingScripts = $jsonContent["scripts"][$key] ?? []; // keep existing scripts $result = []; @@ -94,6 +97,9 @@ function updateProjectComposerJsonScripts (string $key, array $scripts) : void } /** + * Writes the given config to the project composer.json + * + * @param array $config */ private function writeProjectComposerJson (array $config) : void { @@ -109,21 +115,26 @@ private function writeProjectComposerJson (array $config) : void } /** + * @return array */ private function readProjectComposerJson () : array { $filePath = "{$this->cwd}/composer.json"; - return \json_decode( - \file_get_contents($filePath), + $result = \json_decode( + (string) \file_get_contents($filePath), true, - flags: \JSON_THROW_ON_ERROR + flags: \JSON_THROW_ON_ERROR, ); + \assert(\is_array($result)); + return $result; } /** * Runs a composer command in the project + * + * @param string[] $cmd */ public function runComposerInProject (array $cmd) : void { @@ -143,6 +154,8 @@ public function runComposerInProject (array $cmd) : void /** * Runs the given command in the project directory + * + * @param string[] $cmd */ public function runProcessInProject (array $cmd) : void { diff --git a/vendor-bin/c-norm/composer.json b/vendor-bin/c-norm/composer.json new file mode 100644 index 0000000..29d96fe --- /dev/null +++ b/vendor-bin/c-norm/composer.json @@ -0,0 +1,11 @@ +{ + "require-dev": { + "ergebnis/composer-normalize": "^2.42", + "roave/security-advisories": "dev-latest" + }, + "config": { + "allow-plugins": { + "ergebnis/composer-normalize": true + } + } +} diff --git a/vendor-bin/cs-fixer/composer.json b/vendor-bin/cs-fixer/composer.json new file mode 100644 index 0000000..c8efe94 --- /dev/null +++ b/vendor-bin/cs-fixer/composer.json @@ -0,0 +1,6 @@ +{ + "require-dev": { + "21torr/php-cs-fixer": "^1.0.2", + "roave/security-advisories": "dev-latest" + } +} diff --git a/vendor-bin/phpstan/composer.json b/vendor-bin/phpstan/composer.json new file mode 100644 index 0000000..cf165ff --- /dev/null +++ b/vendor-bin/phpstan/composer.json @@ -0,0 +1,21 @@ +{ + "require": { + "php": "^8.3" + }, + "require-dev": { + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-deprecation-rules": "^1.2", + "phpstan/phpstan-doctrine": "^1.4", + "phpstan/phpstan-phpunit": "^1.4", + "phpstan/phpstan-symfony": "^1.4", + "roave/security-advisories": "dev-latest", + "staabm/phpstan-todo-by": "^0.1.25" + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "phpstan/extension-installer": true + } + } +} From 6b39a2523a945ec84783b9d6992aa0e18ed2911e Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Tue, 4 Jun 2024 10:40:05 +0200 Subject: [PATCH 2/6] Add changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8ca1fd..3ce646a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +2.0.0 +===== + +* (bc) Renamed the call from `init-symfony` to `init symfony`. +* (bc) Renamed the call from `init-library` to `init library`. +* (internal) Refactored whole implementation. +* (internal) Run CI on Janus itself. + + 1.3.0 ===== From 425c835d1901a3ce03014d82908d251d59c60b36 Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Tue, 4 Jun 2024 10:41:33 +0200 Subject: [PATCH 3/6] Fix import --- bin/janus | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/janus b/bin/janus index 04bfff2..aaa09f5 100755 --- a/bin/janus +++ b/bin/janus @@ -2,7 +2,6 @@ add(new InitializeCommand()); -$application->add(new LegacyCommand()); $application->run(); From c532e34749c1411c1c7a4a5058330c2f27261d2e Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Tue, 4 Jun 2024 10:48:19 +0200 Subject: [PATCH 4/6] Add choice + deprecated commands --- src/Command/InitializeCommand.php | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Command/InitializeCommand.php b/src/Command/InitializeCommand.php index eec9d68..ce1b020 100644 --- a/src/Command/InitializeCommand.php +++ b/src/Command/InitializeCommand.php @@ -12,6 +12,15 @@ final class InitializeCommand extends Command { + private const array ALLOWED_TYPES = [ + "symfony", + "library", + ]; + private const array LEGACY_COMMANDS = [ + "init-symfony", + "init-library", + ]; + /** */ public function __construct () @@ -26,15 +35,13 @@ protected function configure () : void { $this ->setDescription("Initializes a given command") + ->setAliases(self::LEGACY_COMMANDS) ->addArgument( "type", - InputArgument::REQUIRED, + InputArgument::OPTIONAL, "The project type to initialize", default: null, - suggestedValues: [ - "symfony", - "library", - ], + suggestedValues: self::ALLOWED_TYPES, ); } @@ -46,16 +53,26 @@ protected function execute (InputInterface $input, OutputInterface $output) : in $io = new TorrStyle($input, $output); $io->title("Janus: Initialize"); - try + if (\in_array($input->getFirstArgument(), self::LEGACY_COMMANDS, true)) + { + $io->caution("You are using a deprecated command. Use the `init` command instead."); + } + + $type = $input->getArgument("type"); + + while (!\in_array($type, self::ALLOWED_TYPES, true)) { - $type = $input->getArgument("type"); - \assert(\is_string($type)); + $type = $io->choice("Please select the type to initialize", self::ALLOWED_TYPES); + } + + \assert(\is_string($type)); + try + { $initializer = match ($type) { "symfony" => new SymfonyInitializer(), "library" => new LibraryInitializer(), - default => null, }; if (null === $initializer) From 23030f1fb220c165f29095e1fb7066a9b20fd510 Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Tue, 4 Jun 2024 10:50:50 +0200 Subject: [PATCH 5/6] Add choice for calling init without argument --- CHANGELOG.md | 8 +++++--- src/Command/InitializeCommand.php | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ce646a..fe0bf2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,10 @@ -2.0.0 +1.4.0 ===== -* (bc) Renamed the call from `init-symfony` to `init symfony`. -* (bc) Renamed the call from `init-library` to `init library`. +* (feature) Rename the call from `init-symfony` to `init symfony`. +* (feature) Rename the call from `init-library` to `init library`. +* (feature) Add BC layer for old commands. +* (feature) Add choice for when calling `init` without or with invalid type. * (internal) Refactored whole implementation. * (internal) Run CI on Janus itself. diff --git a/src/Command/InitializeCommand.php b/src/Command/InitializeCommand.php index ce1b020..2f08458 100644 --- a/src/Command/InitializeCommand.php +++ b/src/Command/InitializeCommand.php @@ -60,8 +60,13 @@ protected function execute (InputInterface $input, OutputInterface $output) : in $type = $input->getArgument("type"); - while (!\in_array($type, self::ALLOWED_TYPES, true)) + if (!\in_array($type, self::ALLOWED_TYPES, true)) { + if (null !== $type) + { + $io->error("Used invalid type: {$type}"); + } + $type = $io->choice("Please select the type to initialize", self::ALLOWED_TYPES); } From 3962817003c3ca5d6aec749894dd5facfc92069c Mon Sep 17 00:00:00 2001 From: Jannik Zschiesche Date: Tue, 4 Jun 2024 10:53:20 +0200 Subject: [PATCH 6/6] Improve implementation --- src/Command/InitializeCommand.php | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/Command/InitializeCommand.php b/src/Command/InitializeCommand.php index 2f08458..ba09a79 100644 --- a/src/Command/InitializeCommand.php +++ b/src/Command/InitializeCommand.php @@ -59,6 +59,7 @@ protected function execute (InputInterface $input, OutputInterface $output) : in } $type = $input->getArgument("type"); + \assert(null === $type || \is_string($type)); if (!\in_array($type, self::ALLOWED_TYPES, true)) { @@ -74,18 +75,11 @@ protected function execute (InputInterface $input, OutputInterface $output) : in try { - $initializer = match ($type) + return match ($type) { - "symfony" => new SymfonyInitializer(), - "library" => new LibraryInitializer(), + "symfony" => (new SymfonyInitializer())->initialize($io), + "library" => (new LibraryInitializer())->initialize($io), }; - - if (null === $initializer) - { - return $this->printError($io, $type); - } - - return $initializer->initialize($io); } catch (\Throwable $exception) { @@ -93,14 +87,4 @@ protected function execute (InputInterface $input, OutputInterface $output) : in return 2; } } - - /** - * Prints an error - */ - private function printError (TorrStyle $io, string $type) : int - { - $io->error("Unknown type: {$type}"); - - return self::FAILURE; - } }