overtrue / phplint

:bug: A tool that can speed up linting of php files by running several lint processes at once.
MIT License
984 stars 118 forks source link

Don't forget to change Console Application version before publishing a new release #199

Closed llaville closed 9 months ago

llaville commented 9 months ago

As lot of others application that provide a Symfony Console Application, PHPLint suffer to a hard-coded concept about Application versionning.

Look at https://github.com/overtrue/phplint/blob/9.1/src/Console/Application.php#L39

As maintainer of application, if we forgot to change VERSION value before publish a new version, we will keep an outdated version number on all official versions : including PHAR and Docker distributions.

To avoid such issue, here is my proposal :

Add a new PHP CS Fixer to check and fix Application::VERSION on a git push hook via Composer.

diff --git a/composer.json b/composer.json
index 1d6d4e4..0c27795 100644
--- a/composer.json
+++ b/composer.json
@@ -54,6 +54,9 @@
       "pre-commit": [
         "composer style:fix",
         "composer code:check"
+      ],
+      "pre-push": [
+        "composer qa:check"
       ]
     },
     "branch-alias": {
@@ -73,6 +76,8 @@
       "@composer bin all install --ansi"
     ],
     "cghooks": "vendor/bin/cghooks",
+    "qa:check": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.release.php --using-cache=no --verbose --ansi --diff --dry-run",
+    "qa:fix": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.release.php --using-cache=no --verbose --ansi",
     "style:check": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --using-cache=no --verbose --ansi --diff --dry-run",
     "style:fix": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --using-cache=no --verbose --ansi",
     "tests:unit": "vendor/bin/phpunit --testsuite=cache,configuration,finder",
@@ -84,6 +89,8 @@
   "minimum-stability": "dev",
   "prefer-stable": true,
   "scripts-descriptions": {
+    "qa:check": "Run QA style checks before pushing new tag and releasing a new version (only dry run - no fixing!).",
+    "qa:fix": "Run QA style checks and fix violations.",
     "style:check": "Run style checks (only dry run - no fixing!).",
     "style:fix": "Run style checks and fix violations.",
     "tests:unit": "Run unit tests on following components: cache, configuration, finder",

With new PHP CS Fixer config file .php-cs-fixer.release.php

<?php

require_once 'vendor-bin/php-cs-fixer/src/ApplicationVersionFixer.php';

use Overtrue\CodingStandard\Fixer\ApplicationVersionFixer;

return (new PhpCsFixer\Config())
    ->registerCustomFixers([
        new ApplicationVersionFixer(),
    ])
    ->setRules([
        ApplicationVersionFixer::name() => true,
    ])
    ->setFinder(
        PhpCsFixer\Finder::create()
            ->in([__DIR__.'/src/Console'])
    )
;

And new Fixer

<?php

namespace Overtrue\CodingStandard\Fixer;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use SplFileInfo;

/**
 * @link https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/cookbook_fixers.rst
 * @link https://tomasvotruba.com/blog/2017/07/24/how-to-write-custom-fixer-for-php-cs-fixer-24
 *
 * @author Laurent Laville
 * @since Release 9.1.0
 */
final class ApplicationVersionFixer extends AbstractFixer
{
    /**
     * @inheritDoc
     */
    public function isCandidate(Tokens $tokens): bool
    {
        return $tokens->isAllTokenKindsFound([T_CLASS, T_CONSTANT_ENCAPSED_STRING]);
    }

    /**
     * @inheritDoc
     */
    public function isRisky(): bool
    {
        return false;
    }

    protected function applyFix(SplFileInfo $file, Tokens $tokens): void
    {
        foreach ($tokens as $index => $token) {
            if (!$token->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
                continue;
            }
            if (!$this->isVersionConst($tokens, $index)) {
                continue;
            }

            $tag = @exec('git describe --tags --abbrev=0 2>&1');

            if ($token->getContent() !== $tag) {
                $tokens[$index] = new Token([$token->getId(), "'$tag'"]);
            }
        }
    }

    private function isVersionConst(Tokens $tokens, int $index): bool
    {
        $prevTokenIndex = $tokens->getPrevMeaningfulToken($index);
        if (!$tokens[$prevTokenIndex]->equals('=')) {
            return false;
        }

        $constantNamePosition = $tokens->getPrevMeaningfulToken($prevTokenIndex);
        return $tokens[$constantNamePosition]->equals([T_STRING, 'VERSION']);
    }

    /**
     * @inheritDoc
     */
    public function getDefinition(): FixerDefinitionInterface
    {
        return new FixerDefinition(
            'Application::VERSION constant value must match the current git tag.',
            []
        );
    }

    /**
     * @inheritDoc
     */
    public function getName(): string
    {
        return self::name();
    }

    public static function name(): string
    {
        return 'OvertrueCsFixer/application_version';
    }

    /**
     * @inheritDoc
     */
    public function supports(SplFileInfo $file): bool
    {
        return $file->getBasename() === 'Application.php';
    }

    /**
     * @inheritDoc
     */
    public function getPriority(): int
    {
        return 0;
    }
}

TIP When we still want to push additional code to repository before the final release, we can by pass the qa:check failures if any, with the --no-verify option of git push command.

This is the same solution, if we want to by pass style:fix on pre-commit git hook : git commit --no-verify

@overtrue Tell me if you're agree to add a such solution !

llaville commented 9 months ago

Here is a preview of the new Composer script in action

composer_qa_check

The results are obtained before to tagging the code with git tag -a 9.1.0 command (i.e)

overtrue commented 9 months ago

No problem

Laurent Laville @.***>于2023年12月16日 周六22:54写道:

Here is a preview of the new Composer script in action

composer_qa_check.png (view on web) https://github.com/overtrue/phplint/assets/364342/6c0390cf-83cf-477f-973d-16abf48cd22f

The results are obtained before to tagging the code with git tag -a 9.1.0 command (i.e)

— Reply to this email directly, view it on GitHub https://github.com/overtrue/phplint/issues/199#issuecomment-1858836787, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALHOYFMCRTAGDVIV253A3TYJWYY7AVCNFSM6AAAAABAXUNCLOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNJYHAZTMNZYG4 . You are receiving this because you were mentioned.Message ID: @.***>