From dc3d49bd3300e876a45585768edf18c5af6020d8 Mon Sep 17 00:00:00 2001 From: webimpress Date: Thu, 29 Mar 2018 14:54:07 +0100 Subject: [PATCH 1/4] Added LicenseHeader and MD files sniffs --- COPYRIGHT.md | 1 + composer.json | 1 + phpcs.xml | 9 +- ruleset.xml | 4 + .../Sniffs/Commenting/LicenseHeaderSniff.php | 147 ++++++++++++++++ .../Sniffs/Files/MdSniff.php | 166 ++++++++++++++++++ src/ZendCodingStandard/Tokenizer/MD.php | 45 +++++ src/ZendCodingStandard/helper.php | 29 +++ src/ZendCodingStandard/ruleset.xml | 3 + .../Commenting/LicenseHeaderUnitTest.1.inc | 9 + .../LicenseHeaderUnitTest.1.inc.fixed | 9 + .../Commenting/LicenseHeaderUnitTest.2.inc | 9 + .../LicenseHeaderUnitTest.2.inc.fixed | 14 ++ .../Commenting/LicenseHeaderUnitTest.3.inc | 6 + .../LicenseHeaderUnitTest.3.inc.fixed | 6 + .../Commenting/LicenseHeaderUnitTest.inc | 1 + .../LicenseHeaderUnitTest.inc.fixed | 6 + .../Commenting/LicenseHeaderUnitTest.php | 31 ++++ 18 files changed, 493 insertions(+), 3 deletions(-) create mode 100644 COPYRIGHT.md create mode 100644 src/ZendCodingStandard/Sniffs/Commenting/LicenseHeaderSniff.php create mode 100644 src/ZendCodingStandard/Sniffs/Files/MdSniff.php create mode 100644 src/ZendCodingStandard/Tokenizer/MD.php create mode 100644 src/ZendCodingStandard/helper.php create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.1.inc create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.1.inc.fixed create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.2.inc create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.2.inc.fixed create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.3.inc create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.3.inc.fixed create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.inc create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.inc.fixed create mode 100644 test/Sniffs/Commenting/LicenseHeaderUnitTest.php diff --git a/COPYRIGHT.md b/COPYRIGHT.md new file mode 100644 index 00000000..19370cc3 --- /dev/null +++ b/COPYRIGHT.md @@ -0,0 +1 @@ +Copyright (c) 2018, Zend Technologies USA, Inc. diff --git a/composer.json b/composer.json index 7209b89d..b32e13f7 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "phpunit/phpunit": "^7.0.1" }, "autoload": { + "files": ["src/ZendCodingStandard/helper.php"], "psr-4": { "ZendCodingStandard\\": "src/ZendCodingStandard/" } diff --git a/phpcs.xml b/phpcs.xml index 13388786..849465f6 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -4,8 +4,11 @@ xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd"> - src - test - + . test/*.inc + vendor/ + + + src/ZendCodingStandard/helper.php + diff --git a/ruleset.xml b/ruleset.xml index 35c6319a..92248c0d 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -1,4 +1,8 @@ + + ../../../ + vendor/ + test/**/TestAsset/ diff --git a/src/ZendCodingStandard/Sniffs/Commenting/LicenseHeaderSniff.php b/src/ZendCodingStandard/Sniffs/Commenting/LicenseHeaderSniff.php new file mode 100644 index 00000000..e0dabf08 --- /dev/null +++ b/src/ZendCodingStandard/Sniffs/Commenting/LicenseHeaderSniff.php @@ -0,0 +1,147 @@ +getTokens(); + $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); + + if ($tokens[$next]['code'] === T_DECLARE) { + $string = $phpcsFile->findNext( + T_STRING, + $tokens[$next]['parenthesis_opener'] + 1, + $tokens[$next]['parenthesis_closer'] + ); + + // If the first statement in the file is strict type declaration. + if ($string && stripos($tokens[$string]['content'], 'strict_types') !== false) { + $eos = $phpcsFile->findEndOfStatement($next); + $next = $phpcsFile->findNext(T_WHITESPACE, $eos + 1, null, true); + } + } + + if ($next && $tokens[$next]['code'] === T_DOC_COMMENT_OPEN_TAG) { + $prev = $phpcsFile->findPrevious(T_WHITESPACE, $next - 1, null, true); + if ($tokens[$prev]['code'] === T_OPEN_TAG + && $tokens[$prev]['line'] + 1 !== $tokens[$next]['line'] + ) { + $error = 'License header must be in next line after opening PHP tag'; + $fix = $phpcsFile->addFixableError($error, $next, 'Line'); + + if ($fix) { + $phpcsFile->fixer->beginChangeset(); + for ($i = $next - 1; $i > $prev; --$i) { + $phpcsFile->fixer->replaceToken($i, ''); + } + $phpcsFile->fixer->endChangeset(); + } + } + + $content = $phpcsFile->getTokensAsString($next, $tokens[$next]['comment_closer'] - $next + 1); + $comment = $this->getComment(); + + if ($comment === $content) { + return $phpcsFile->numTokens + 1; + } + + if ($this->hasTags($phpcsFile, $next)) { + $error = 'Invalid doc license header'; + $fix = $phpcsFile->addFixableError($error, $next, 'Invalid'); + + if ($fix) { + $phpcsFile->fixer->beginChangeset(); + for ($i = $next; $i < $tokens[$next]['comment_closer']; ++$i) { + $phpcsFile->fixer->replaceToken($i, ''); + } + $phpcsFile->fixer->replaceToken($tokens[$next]['comment_closer'], $comment); + $phpcsFile->fixer->endChangeset(); + } + + return $phpcsFile->numTokens + 1; + } + } + + $error = 'Missing license header'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Missing'); + + if ($fix) { + $phpcsFile->fixer->addContent($stackPtr, $this->getComment() . $phpcsFile->eolChar); + } + + return $phpcsFile->numTokens + 1; + } + + private function getComment() : string + { + return strtr($this->comment, array_merge($this->getDefaultVariables(), $this->variables)); + } + + private function hasTags(File $phpcsFile, int $comment) : bool + { + $tokens = $phpcsFile->getTokens(); + $tags = ['@copyright' => true, '@license' => true]; + + foreach ($tokens[$comment]['comment_tags'] ?? [] as $token) { + $content = strtolower($tokens[$token]['content']); + unset($tags[$content]); + } + + return ! $tags; + } + + private function getDefaultVariables() : array + { + return [ + '{org}' => Config::getConfigData('zfcs:org') ?: 'zendframework', + '{repo}' => Config::getConfigData('zfcs:repo'), + ]; + } +} diff --git a/src/ZendCodingStandard/Sniffs/Files/MdSniff.php b/src/ZendCodingStandard/Sniffs/Files/MdSniff.php new file mode 100644 index 00000000..9847a32c --- /dev/null +++ b/src/ZendCodingStandard/Sniffs/Files/MdSniff.php @@ -0,0 +1,166 @@ + 'https://raw.githubusercontent.com/zendframework/maintainers/master/template/LICENSE.md', + 'COPYRIGHT.md' => 'Copyright (c) {year}, Zend Technologies USA, Inc.' . "\n", + 'CODE_OF_CONDUCT.md' => 'https://raw.githubusercontent.com/zendframework/maintainers/master/template/docs/CODE_OF_CONDUCT.md', + 'CONTRIBUTING.md' => 'https://raw.githubusercontent.com/zendframework/maintainers/master/template/docs/CONTRIBUTING.md', + 'ISSUE_TEMPLATE.md' => 'https://raw.githubusercontent.com/zendframework/maintainers/master/template/docs/ISSUE_TEMPLATE.md', + 'PULL_REQUEST_TEMPLATE.md' => 'https://raw.githubusercontent.com/zendframework/maintainers/master/template/docs/PULL_REQUEST_TEMPLATE.md', + 'SUPPORT.md' => 'https://raw.githubusercontent.com/zendframework/maintainers/master/template/docs/SUPPORT.md', + // @phpcs:enable + ]; + + /** + * @var string[] + */ + public $variables = []; + + /** + * @return int[] + */ + public function register() : array + { + return [T_MD_LINE]; + } + + /** + * @param int $stackPtr + * @return int + */ + public function process(File $phpcsFile, $stackPtr) + { + $template = $this->getTemplate($phpcsFile->getFilename()); + if ($template === null) { + $tokens = $phpcsFile->getTokens(); + + do { + $content = $tokens[$stackPtr]['content']; + $expected = rtrim($content) . (substr($content, -1) === "\n" ? "\n" : ''); + + if ($content !== $expected) { + $error = 'White characters found at the end of the line'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'WhiteChars'); + + if ($fix) { + $phpcsFile->fixer->replaceToken($stackPtr, $expected); + } + } + } while ($stackPtr = $phpcsFile->findNext(T_MD_LINE, $stackPtr + 1)); + + if (trim($tokens[$phpcsFile->numTokens - 1]['content']) !== '') { + $error = 'Missing empty line at the end of the file'; + $fix = $phpcsFile->addFixableError($error, $phpcsFile->numTokens - 1, 'MissingEmptyLine'); + + if ($fix) { + $phpcsFile->fixer->addNewline($phpcsFile->numTokens - 1); + } + } elseif ($phpcsFile->numTokens > 1 && trim($tokens[$phpcsFile->numTokens - 2]['content']) === '') { + $error = 'Redundant empty line at the end of the file'; + $fix = $phpcsFile->addFixableError($error, $phpcsFile->numTokens - 1, 'RedundantEmptyLine'); + + if ($fix) { + $phpcsFile->fixer->replaceToken($phpcsFile->numTokens - 2, ''); + } + } + + return $phpcsFile->numTokens + 1; + } + + $content = $phpcsFile->getTokensAsString(0, $phpcsFile->numTokens); + + $variables = $this->variables; + if (preg_match('/\s(\d{4})(-\d{4})?/', $content, $match)) { + $year = $match[1]; + $currentYear = gmdate('Y'); + if ($year < $currentYear) { + $year .= '-' . $currentYear; + } + $variables['{year}'] = $year; + } + + $newContent = strtr($template, array_merge($this->getDefaultVariables(), $variables)); + + if ($content !== $newContent) { + $error = 'Content is outdated; found %s; expected %s'; + $data = [$content, $newContent]; + $code = ucfirst(strtolower(strstr(basename($phpcsFile->getFilename()), '.', true))); + $fix = $phpcsFile->addFixableError($error, $stackPtr, $code, $data); + + if ($fix) { + $phpcsFile->fixer->beginChangeset(); + for ($i = 0; $i < $phpcsFile->numTokens; ++$i) { + $phpcsFile->fixer->replaceToken($i, ''); + } + $phpcsFile->fixer->addContent(0, $newContent); + $phpcsFile->fixer->endChangeset(); + } + } + + return $phpcsFile->numTokens + 1; + } + + private function getTemplate(string $filename) : ?string + { + foreach ($this->templates as $name => $template) { + if (strpos($filename, '/' . $name) !== false) { + if (filter_var($template, FILTER_VALIDATE_URL)) { + return file_get_contents($template); + } + + return $template; + } + } + + return null; + } + + private function getDefaultVariables() : array + { + return [ + '{category}' => Config::getConfigData('zfcs:category') ?: 'components', + '{org}' => Config::getConfigData('zfcs:org') ?: 'zendframework', + '{repo}' => Config::getConfigData('zfcs:repo'), + '{year}' => gmdate('Y'), + ]; + } +} diff --git a/src/ZendCodingStandard/Tokenizer/MD.php b/src/ZendCodingStandard/Tokenizer/MD.php new file mode 100644 index 00000000..c434a2c9 --- /dev/null +++ b/src/ZendCodingStandard/Tokenizer/MD.php @@ -0,0 +1,45 @@ + &$line) { + $line = [ + 'content' => $line . "\n", + 'code' => T_MD_LINE, + 'type' => 'T_MD_LINE', + ]; + } + + $line['content'] = preg_replace('/\n$/', '', $line['content']); + + return $lines; + } + + /** + * Performs additional processing after main tokenizing. + */ + protected function processAdditional() + { + } +} diff --git a/src/ZendCodingStandard/helper.php b/src/ZendCodingStandard/helper.php new file mode 100644 index 00000000..804e3796 --- /dev/null +++ b/src/ZendCodingStandard/helper.php @@ -0,0 +1,29 @@ + Zend Framework Coding Standard + + + diff --git a/test/Sniffs/Commenting/LicenseHeaderUnitTest.1.inc b/test/Sniffs/Commenting/LicenseHeaderUnitTest.1.inc new file mode 100644 index 00000000..282e0f4c --- /dev/null +++ b/test/Sniffs/Commenting/LicenseHeaderUnitTest.1.inc @@ -0,0 +1,9 @@ + 1]; + case 'LicenseHeaderUnitTest.3.inc': + return [3 => 2]; + } + + return [ + 1 => 1, + ]; + } + + public function getWarningList(string $testFile = '') : array + { + return []; + } +} From 3a0222974ff50198e4451e26d60fe2e739cf31d3 Mon Sep 17 00:00:00 2001 From: webimpress Date: Thu, 29 Mar 2018 16:00:33 +0100 Subject: [PATCH 2/4] Added license headers to all files It's done automatically by cs-fix --- src/ZendCodingStandard/CodingStandard.php | 5 +++++ src/ZendCodingStandard/Helper/Methods.php | 5 +++++ src/ZendCodingStandard/Helper/Namespaces.php | 5 +++++ src/ZendCodingStandard/Sniffs/Arrays/DoubleArrowSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Arrays/FormatSniff.php | 5 +++++ .../Sniffs/Arrays/TrailingArrayCommaSniff.php | 5 +++++ .../Sniffs/Classes/AlphabeticallySortedTraitsSniff.php | 5 +++++ .../Sniffs/Classes/ConstVisibilitySniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Classes/NoNullValuesSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Classes/TraitUsageSniff.php | 5 +++++ .../Sniffs/Commenting/CodingStandardTagsSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Commenting/DocCommentSniff.php | 5 +++++ .../Sniffs/Commenting/FunctionCommentSniff.php | 5 +++++ .../Sniffs/Commenting/FunctionDataProviderTagSniff.php | 5 +++++ .../Sniffs/Commenting/FunctionDisallowedTagSniff.php | 5 +++++ .../Sniffs/Commenting/LicenseHeaderSniff.php | 5 +++++ .../Commenting/NoInlineCommentAfterCurlyCloseSniff.php | 5 +++++ .../Sniffs/Commenting/PhpcsAnnotationSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Commenting/TagCaseSniff.php | 5 +++++ .../Sniffs/Commenting/TagWithTypeSniff.php | 5 +++++ .../Sniffs/Commenting/VariableCommentSniff.php | 5 +++++ .../Sniffs/Files/DeclareStrictTypesSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Files/MdSniff.php | 5 +++++ .../Sniffs/Formatting/DoubleColonSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Formatting/HeredocSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Formatting/NewKeywordSniff.php | 5 +++++ .../Sniffs/Formatting/NoSpaceAfterSplatSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Formatting/ReferenceSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Formatting/ReturnTypeSniff.php | 5 +++++ .../Sniffs/Formatting/UnnecessaryParenthesesSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Functions/ParamSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Functions/ReturnTypeSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Functions/ThrowsSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/Methods/LineAfterSniff.php | 5 +++++ .../Sniffs/Namespaces/AlphabeticallySortedUsesSniff.php | 5 +++++ .../Sniffs/Namespaces/ConstAndFunctionKeywordsSniff.php | 5 +++++ .../Sniffs/Namespaces/UnusedUseStatementSniff.php | 5 +++++ .../Sniffs/Namespaces/UseDoesNotStartWithBackslashSniff.php | 5 +++++ .../Sniffs/NamingConventions/ValidVariableNameSniff.php | 5 +++++ .../Sniffs/Operators/BooleanOperatorSniff.php | 5 +++++ .../Sniffs/Operators/TernaryOperatorSniff.php | 5 +++++ .../Sniffs/PHP/CorrectClassNameCaseSniff.php | 5 +++++ .../Sniffs/PHP/DeclareStrictTypesSniff.php | 5 +++++ .../Sniffs/PHP/ImportInternalConstantSniff.php | 5 +++++ .../Sniffs/PHP/ImportInternalFunctionSniff.php | 5 +++++ .../Sniffs/PHP/InstantiatingParenthesisSniff.php | 5 +++++ .../Sniffs/PHP/RedundantSemicolonSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/PHP/SingleSemicolonSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/PHP/TypeCastingSniff.php | 5 +++++ .../Sniffs/Strings/NoConcatenationAtTheEndSniff.php | 5 +++++ src/ZendCodingStandard/Sniffs/WhiteSpace/BlankLineSniff.php | 5 +++++ .../Sniffs/WhiteSpace/CommaSpacingSniff.php | 5 +++++ .../Sniffs/WhiteSpace/NoBlankLineAtStartSniff.php | 5 +++++ .../Sniffs/WhiteSpace/ScopeIndentSniff.php | 5 +++++ src/ZendCodingStandard/Tokenizer/MD.php | 5 +++++ src/ZendCodingStandard/helper.php | 5 +++++ test/Ruleset.php | 5 +++++ test/Sniffs/Arrays/DoubleArrowUnitTest.php | 5 +++++ test/Sniffs/Arrays/FormatUnitTest.php | 5 +++++ test/Sniffs/Arrays/TrailingArrayCommaUnitTest.php | 5 +++++ test/Sniffs/Classes/AlphabeticallySortedTraitsUnitTest.php | 5 +++++ test/Sniffs/Classes/ConstVisibilityUnitTest.php | 5 +++++ test/Sniffs/Classes/NoNullValuesUnitTest.php | 5 +++++ test/Sniffs/Classes/TraitUsageUnitTest.php | 5 +++++ test/Sniffs/Commenting/CodingStandardTagsUnitTest.php | 5 +++++ test/Sniffs/Commenting/DocCommentUnitTest.php | 5 +++++ test/Sniffs/Commenting/FunctionCommentUnitTest.php | 5 +++++ test/Sniffs/Commenting/FunctionDataProviderTagUnitTest.php | 5 +++++ test/Sniffs/Commenting/FunctionDisallowedTagUnitTest.php | 5 +++++ test/Sniffs/Commenting/LicenseHeaderUnitTest.php | 5 +++++ .../Commenting/NoInlineCommentAfterCurlyCloseUnitTest.php | 5 +++++ test/Sniffs/Commenting/PhpcsAnnotationUnitTest.php | 5 +++++ test/Sniffs/Commenting/TagCaseUnitTest.php | 5 +++++ test/Sniffs/Commenting/TagWithTypeUnitTest.php | 5 +++++ test/Sniffs/Commenting/VariableCommentUnitTest.php | 5 +++++ test/Sniffs/Files/DeclareStrictTypesUnitTest.php | 5 +++++ test/Sniffs/Formatting/DoubleColonUnitTest.php | 5 +++++ test/Sniffs/Formatting/HeredocUnitTest.php | 5 +++++ test/Sniffs/Formatting/NewKeywordUnitTest.php | 5 +++++ test/Sniffs/Formatting/NoSpaceAfterSplatUnitTest.php | 5 +++++ test/Sniffs/Formatting/ReferenceUnitTest.php | 5 +++++ test/Sniffs/Formatting/ReturnTypeUnitTest.php | 5 +++++ test/Sniffs/Formatting/UnnecessaryParenthesesUnitTest.php | 5 +++++ test/Sniffs/Functions/ParamUnitTest.php | 5 +++++ test/Sniffs/Functions/ReturnTypeUnitTest.php | 5 +++++ test/Sniffs/Functions/ThrowsUnitTest.php | 5 +++++ test/Sniffs/Methods/LineAfterUnitTest.php | 5 +++++ test/Sniffs/Namespaces/AlphabeticallySortedUsesUnitTest.php | 5 +++++ test/Sniffs/Namespaces/ConstAndFunctionKeywordsUnitTest.php | 5 +++++ test/Sniffs/Namespaces/UnusedUseStatementUnitTest.php | 5 +++++ .../Namespaces/UseDoesNotStartWithBackslashUnitTest.php | 5 +++++ test/Sniffs/NamingConventions/ValidVariableNameUnitTest.php | 5 +++++ test/Sniffs/Operators/BooleanOperatorUnitTest.php | 5 +++++ test/Sniffs/Operators/TernaryOperatorUnitTest.php | 5 +++++ test/Sniffs/PHP/CorrectClassNameCaseUnitTest.php | 5 +++++ test/Sniffs/PHP/DeclareStrictTypesUnitTest.php | 5 +++++ test/Sniffs/PHP/ImportInternalConstantUnitTest.php | 5 +++++ test/Sniffs/PHP/ImportInternalFunctionUnitTest.php | 5 +++++ test/Sniffs/PHP/InstantiatingParenthesisUnitTest.php | 5 +++++ test/Sniffs/PHP/RedundantSemicolonUnitTest.php | 5 +++++ test/Sniffs/PHP/SingleSemicolonUnitTest.php | 5 +++++ test/Sniffs/PHP/TypeCastingUnitTest.php | 5 +++++ test/Sniffs/Strings/NoConcatenationAtTheEndUnitTest.php | 5 +++++ test/Sniffs/TestCase.php | 5 +++++ test/Sniffs/WhiteSpace/BlankLineUnitTest.php | 5 +++++ test/Sniffs/WhiteSpace/CommaSpacingUnitTest.php | 5 +++++ test/Sniffs/WhiteSpace/NoBlankLineAtStartUnitTest.php | 5 +++++ test/Sniffs/WhiteSpace/ScopeIndentUnitTest.php | 5 +++++ 108 files changed, 540 insertions(+) diff --git a/src/ZendCodingStandard/CodingStandard.php b/src/ZendCodingStandard/CodingStandard.php index e1919fd4..a72729f7 100644 --- a/src/ZendCodingStandard/CodingStandard.php +++ b/src/ZendCodingStandard/CodingStandard.php @@ -1,4 +1,9 @@ Date: Tue, 3 Apr 2018 10:19:24 +0100 Subject: [PATCH 3/4] Added Files/Create sniff to create required files if these do not exist --- .../Sniffs/Files/CreateSniff.php | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/ZendCodingStandard/Sniffs/Files/CreateSniff.php diff --git a/src/ZendCodingStandard/Sniffs/Files/CreateSniff.php b/src/ZendCodingStandard/Sniffs/Files/CreateSniff.php new file mode 100644 index 00000000..e1ee42d1 --- /dev/null +++ b/src/ZendCodingStandard/Sniffs/Files/CreateSniff.php @@ -0,0 +1,88 @@ +run) { + return $phpcsFile->numTokens + 1; + } + $this->run = true; + + foreach ($this->files as $file) { + if (! file_exists($file)) { + $error = 'File %s does not exist'; + $data = [$file]; + $fix = $phpcsFile->addFixableError($error, 0, 'NotExists', $data); + + if ($fix) { + touch($file); + } + } + } + + return $phpcsFile->numTokens + 1; + } +} From a6c1858ad33adb37ceb9cc510b4cf2b2c4676309 Mon Sep 17 00:00:00 2001 From: webimpress Date: Tue, 3 Apr 2018 14:24:13 +0100 Subject: [PATCH 4/4] Use first tag date in year range --- COPYRIGHT.md | 2 +- .../Sniffs/Files/MdSniff.php | 48 +++++++++++++------ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/COPYRIGHT.md b/COPYRIGHT.md index 19370cc3..42bc88cf 100644 --- a/COPYRIGHT.md +++ b/COPYRIGHT.md @@ -1 +1 @@ -Copyright (c) 2018, Zend Technologies USA, Inc. +Copyright (c) 2016-2018, Zend Technologies USA, Inc. diff --git a/src/ZendCodingStandard/Sniffs/Files/MdSniff.php b/src/ZendCodingStandard/Sniffs/Files/MdSniff.php index 93affa1a..712ffef5 100644 --- a/src/ZendCodingStandard/Sniffs/Files/MdSniff.php +++ b/src/ZendCodingStandard/Sniffs/Files/MdSniff.php @@ -9,16 +9,17 @@ namespace ZendCodingStandard\Sniffs\Files; +use DateTime; +use DateTimeZone; use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use function array_merge; use function basename; +use function exec; use function file_get_contents; use function filter_var; -use function gmdate; -use function preg_match; use function rtrim; use function strpos; use function strstr; @@ -60,6 +61,16 @@ class MdSniff implements Sniff */ public $variables = []; + /** + * @var string + */ + public $yearTimezone = 'GMT'; + + /** + * @var null|string + */ + private $yearRange; + /** * @return int[] */ @@ -113,17 +124,7 @@ public function process(File $phpcsFile, $stackPtr) $content = $phpcsFile->getTokensAsString(0, $phpcsFile->numTokens); - $variables = $this->variables; - if (preg_match('/\s(\d{4})(-\d{4})?/', $content, $match)) { - $year = $match[1]; - $currentYear = gmdate('Y'); - if ($year < $currentYear) { - $year .= '-' . $currentYear; - } - $variables['{year}'] = $year; - } - - $newContent = strtr($template, array_merge($this->getDefaultVariables(), $variables)); + $newContent = strtr($template, array_merge($this->getDefaultVariables(), $this->variables)); if ($content !== $newContent) { $error = 'Content is outdated; found %s; expected %s'; @@ -165,7 +166,26 @@ private function getDefaultVariables() : array '{category}' => Config::getConfigData('zfcs:category') ?: 'components', '{org}' => Config::getConfigData('zfcs:org') ?: 'zendframework', '{repo}' => Config::getConfigData('zfcs:repo'), - '{year}' => gmdate('Y'), + '{year}' => $this->getYearRange(), ]; } + + private function getYearRange() : string + { + if (! $this->yearRange) { + $timezone = new DateTimeZone($this->yearTimezone); + + exec('git tag -l --format=\'%(taggerdate)\' | head -n 1', $output, $return); + $date = new DateTime($return === 0 && isset($output[0]) ? $output[0] : 'now'); + $date->setTimezone($timezone); + $this->yearRange = $date->format('Y'); + + $currentYear = (new DateTime('now', $timezone))->format('Y'); + if ($this->yearRange < $currentYear) { + $this->yearRange .= '-' . $currentYear; + } + } + + return $this->yearRange; + } }