diff --git a/.gitattributes b/.gitattributes index 814f5484..09302194 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,16 +5,19 @@ # https://www.reddit.com/r/PHP/comments/2jzp6k/i_dont_need_your_tests_in_my_production # https://blog.madewithlove.be/post/gitattributes/ # -/.coveralls.yml export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.github/ export-ignore -/phpcs.xml.dist export-ignore -/phpunit.xml.dist export-ignore -/phpunit-bootstrap.php export-ignore -/Modernize/Tests/ export-ignore +.coveralls.yml export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.remarkignore export-ignore +.remarkrc export-ignore +.yamllint.yml export-ignore +phpcs.xml.dist export-ignore +phpunit.xml.dist export-ignore +phpunit-bootstrap.php export-ignore +/.github/ export-ignore +/Modernize/Tests/ export-ignore /NormalizedArrays/Tests/ export-ignore -/Universal/Tests/ export-ignore +/Universal/Tests/ export-ignore # # Auto detect text files and perform LF normalization diff --git a/.github/release-checklist.md b/.github/release-checklist.md new file mode 100644 index 00000000..2e8ae524 --- /dev/null +++ b/.github/release-checklist.md @@ -0,0 +1,27 @@ +# Template to use for release PRs from `develop` to `stable` + +PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH DAY YEAR**. + +## Release checklist + +### General + +- [ ] Verify, and if necessary, update the allowed version ranges for various dependencies in the `composer.json` - PR #xxx +- [ ] Add changelog for the release - PR #xxx + :pencil2: Remember to add a release link at the bottom! +- [ ] Update sniff list in `README` (if applicable) - PR #xxx. + +### Release + +- [ ] Merge this PR +- [ ] Make sure all CI builds are green. +- [ ] Tag and create a release (careful, GH defaults to `develop`!) & copy & paste the changelog to it. + :pencil2: Don't forget to copy the link collection from the bottom of the changelog! +- [ ] Make sure all CI builds are green. +- [ ] Close the milestone +- [ ] Open a new milestone for the next release +- [ ] If any open PRs/issues which were milestoned for this release did not make it into the release, update their milestone. +- [ ] Fast-forward `develop` to be equal to `master` + +### Publicize +- [ ] Tweet about the release. diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 9029b26a..ede7f6ac 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -37,6 +37,11 @@ jobs: coverage: none tools: cs2pr + # Validate the composer.json file. + # @link https://getcomposer.org/doc/03-cli.md#validate + - name: Validate Composer installation + run: composer validate --no-check-all --strict + - name: 'Composer: adjust dependencies' run: | # The sniff stage doesn't run the unit tests, so no need for PHPUnit. @@ -49,8 +54,8 @@ jobs: - name: Install Composer dependencies uses: "ramsey/composer-install@v2" with: - # Bust the cache at least once a month - output format: YYYY-MM-DD. - custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") - name: Install xmllint run: | @@ -92,7 +97,80 @@ jobs: - name: Check sniff feature completeness run: composer check-complete - # Validate the composer.json file. - # @link https://getcomposer.org/doc/03-cli.md#validate - - name: Validate Composer installation - run: composer validate --no-check-all --strict + remark: + name: 'QA Markdown' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up node and enable caching of dependencies + uses: actions/setup-node@v3 + with: + node-version: '16' + + # To make the command available on CLI, it needs to be installed globally. + - name: Install Remark CLI globally + run: npm install --global remark-cli --foreground-scripts true --fund false + + # To allow for creating a custom config which references rules which are included + # in the presets, without having to install all rules individually, a local install + # works best (and installing the presets in the first place, of course). + # + # Note: the first group of packages are all part of the mono "Remark lint" repo. + # The second group of packages (heading-whitespace and down) are additional + # "external" rules/plugins. + - name: Install Remark rules locally + run: > + npm install --foreground-scripts true --fund false + remark-lint + remark-gfm + remark-preset-lint-consistent + remark-preset-lint-recommended + remark-preset-lint-markdown-style-guide + remark-lint-checkbox-content-indent + remark-lint-linebreak-style + remark-lint-no-duplicate-defined-urls + remark-lint-no-empty-url + remark-lint-no-heading-like-paragraph + remark-lint-no-reference-like-url + remark-lint-no-unneeded-full-reference-image + remark-lint-no-unneeded-full-reference-link + remark-lint-strikethrough-marker + remark-lint-heading-whitespace + remark-lint-list-item-punctuation + remark-lint-match-punctuation + remark-lint-no-hr-after-heading + remark-lint-are-links-valid-alive + remark-lint-are-links-valid-duplicate + remark-validate-links + + - name: Run Remark-lint + run: remark . --frail + + # @link https://github.com/reviewdog/action-remark-lint + - name: Show Remark-lint annotations in PR + if: ${{ failure() && github.event_name == 'pull_request' }} + uses: reviewdog/action-remark-lint@v5 + with: + fail_on_error: true + install_deps: false + level: info + reporter: github-pr-check + + yamllint: + name: 'Lint Yaml' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # Ref: https://yamllint.readthedocs.io/en/stable/ + - name: Run Yamllint on all yaml files in repo + run: yamllint . --format colored + + - name: Pipe Yamllint results on to GH for inline display + if: ${{ failure() }} + run: yamllint . --format github diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 90c699e0..1ebb95d0 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -64,16 +64,16 @@ jobs: if: matrix.php != 'latest' uses: "ramsey/composer-install@v2" with: - # Bust the cache at least once a month - output format: YYYY-MM-DD. - custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") - # For the PHP "latest", we need to install with ignore platform reqs as not all PHPUnit 7.x dependencies allow it. + # For PHP "latest", we need to install with ignore platform reqs as not all PHPUnit 7.x dependencies allow it. - name: Install Composer dependencies - with ignore platform if: matrix.php == 'latest' uses: "ramsey/composer-install@v2" with: composer-options: --ignore-platform-reqs - custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") + custom-cache-suffix: $(date -u "+%Y-%m") - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc82d4aa..a0f26dc8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,11 +32,13 @@ jobs: # @link https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix # # The matrix is set up so as not to duplicate the builds which are run for code coverage. - php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '8.0', '8.1', '8.2'] + php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '8.0', '8.1', '8.2', '8.3'] phpcs_version: ['3.7.1', 'dev-master'] name: "Test${{ matrix.phpcs_version == 'dev-master' && ' + Lint' || '' }}: PHP ${{ matrix.php }} - PHPCS ${{ matrix.phpcs_version }}" + continue-on-error: ${{ matrix.php == '8.3' }} + steps: - name: Checkout code uses: actions/checkout@v3 @@ -68,8 +70,8 @@ jobs: if: ${{ startsWith( matrix.php, '8' ) == false }} uses: "ramsey/composer-install@v2" with: - # Bust the cache at least once a month - output format: YYYY-MM-DD. - custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") # For the PHP 8/"nightly", we need to install with ignore platform reqs as we're still using PHPUnit 7. - name: Install Composer dependencies - with ignore platform @@ -77,7 +79,7 @@ jobs: uses: "ramsey/composer-install@v2" with: composer-options: --ignore-platform-reqs - custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") + custom-cache-suffix: $(date -u "+%Y-%m") - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' @@ -144,8 +146,8 @@ jobs: - name: Install Composer dependencies uses: "ramsey/composer-install@v2" with: - # Bust the cache at least once a month - output format: YYYY-MM-DD. - custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' diff --git a/.remarkignore b/.remarkignore new file mode 100644 index 00000000..6718a0bb --- /dev/null +++ b/.remarkignore @@ -0,0 +1,5 @@ +# Ignore rules for Remark. +# Docs: https://github.com/unifiedjs/unified-engine/blob/HEAD/doc/ignore.md + +/node_modules/ +/vendor/ diff --git a/.remarkrc b/.remarkrc new file mode 100644 index 00000000..83ab108b --- /dev/null +++ b/.remarkrc @@ -0,0 +1,36 @@ +{ + "plugins": [ + "remark-gfm", + ["remark-lint-checkbox-character-style", "consistent"], + ["remark-lint-checkbox-content-indent", "consistent"], + "remark-lint-definition-spacing", + "remark-lint-file-extension", + ["remark-lint-linebreak-style", "unix"], + ["remark-lint-link-title-style", "\""], + ["remark-lint-ordered-list-marker-style", "."], + "remark-lint-no-duplicate-defined-urls", + "remark-lint-no-duplicate-definitions", + "remark-lint-no-empty-url", + "remark-lint-no-file-name-consecutive-dashes", + "remark-lint-no-file-name-irregular-characters", + "remark-lint-no-file-name-outer-dashes", + "remark-lint-no-heading-like-paragraph", + "remark-lint-no-literal-urls", + "remark-lint-no-reference-like-url", + "remark-lint-no-shortcut-reference-image", + "remark-lint-no-table-indentation", + "remark-lint-no-undefined-references", + "remark-lint-no-unneeded-full-reference-image", + "remark-lint-no-unneeded-full-reference-link", + "remark-lint-no-unused-definitions", + ["remark-lint-strikethrough-marker", "~~"], + ["remark-lint-table-cell-padding", "consistent"], + "remark-lint-heading-whitespace", + "remark-lint-list-item-punctuation", + "remark-lint-match-punctuation", + "remark-lint-no-hr-after-heading", + "remark-lint-are-links-valid-alive", + "remark-lint-are-links-valid-duplicate", + "remark-validate-links" + ] +} diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 00000000..8dc953ff --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,22 @@ +# Details on the default config: +# https://yamllint.readthedocs.io/en/stable/configuration.html#default-configuration +extends: default + +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' + +# Rule documentation: https://yamllint.readthedocs.io/en/stable/rules.html +rules: + colons: + max-spaces-after: -1 # Disabled to allow aligning of values. + comments: + min-spaces-from-content: 1 + comments-indentation: {} + document-start: + present: false + line-length: + max: 145 + truthy: + allowed-values: ["true", "false", "on", "off"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e97109d..68688ba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,38 @@ This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses _Nothing yet._ +## [1.0.0] - 2023-01-04 + +:warning: Important: this package now requires [PHPCSUtils 1.0.0]. Please make sure you use `--with-[all-]dependencies` when running `composer update`. :exclamation: + +For the full list of features, please see the changelogs of the alpha/rc releases: +* [1.0.0-rc1](https://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.0.0-rc1) +* [1.0.0-alpha3](https://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.0.0-alpha3) +* [1.0.0-alpha2](https://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.0.0-alpha2) +* [1.0.0-alpha1](https://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.0.0-alpha1) + +### Changed + +#### Other + +* Updated various sniffs to take advantage of PHPCSUtils 1.0.0(-rc1). [#193], [#194], [#195] +* Minor documentation improvements. +* Various housekeeping. + +### Fixed + +#### Modernize + +* `Modernize.FunctionCalls.Dirname`: the sniff will now correctly recognize magic constants in a case-insensitive manner. [#187] + +[PHPCSUtils 1.0.0]: https://github.com/PHPCSStandards/PHPCSUtils/releases/tag/1.0.0 + +[#187]: https://github.com/PHPCSStandards/PHPCSExtra/pull/187 +[#193]: https://github.com/PHPCSStandards/PHPCSExtra/pull/193 +[#194]: https://github.com/PHPCSStandards/PHPCSExtra/pull/194 +[#195]: https://github.com/PHPCSStandards/PHPCSExtra/pull/195 + + ## [1.0.0-RC1] - 2022-12-07 :warning: Important: this package now requires [PHPCSUtils 1.0.0-alpha4]. Please make sure you use `--with-[all-]dependencies` when running `composer update`. :exclamation: @@ -137,6 +169,7 @@ The upgrade to PHPCSUtils 1.0.0-alpha4 took care of a number of bugs, which pote [#128]: https://github.com/PHPCSStandards/PHPCSExtra/pull/128 [#130]: https://github.com/PHPCSStandards/PHPCSExtra/pull/130 [#134]: https://github.com/PHPCSStandards/PHPCSExtra/pull/134 +[#135]: https://github.com/PHPCSStandards/PHPCSExtra/pull/135 [#137]: https://github.com/PHPCSStandards/PHPCSExtra/pull/137 [#140]: https://github.com/PHPCSStandards/PHPCSExtra/pull/140 [#142]: https://github.com/PHPCSStandards/PHPCSExtra/pull/142 @@ -342,6 +375,7 @@ This initial alpha release contains the following sniffs: [Composer PHPCS plugin]: https://github.com/PHPCSStandards/composer-installer [Unreleased]: https://github.com/PHPCSStandards/PHPCSExtra/compare/stable...HEAD +[1.0.0]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0-rc1...1.0.0 [1.0.0-RC1]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0-alpha3...1.0.0-rc1 [1.0.0-alpha3]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0-alpha2...1.0.0-alpha3 [1.0.0-alpha2]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0-alpha1...1.0.0-alpha2 diff --git a/Modernize/Sniffs/FunctionCalls/DirnameSniff.php b/Modernize/Sniffs/FunctionCalls/DirnameSniff.php index ab944a60..c4001627 100644 --- a/Modernize/Sniffs/FunctionCalls/DirnameSniff.php +++ b/Modernize/Sniffs/FunctionCalls/DirnameSniff.php @@ -118,7 +118,7 @@ public function process(File $phpcsFile, $stackPtr) /* * PHP 5.3+: Detect use of dirname(__FILE__). */ - if ($pathParam['clean'] === '__FILE__') { + if (\strtoupper($pathParam['clean']) === '__FILE__') { // Determine if the issue is auto-fixable. $hasComment = $phpcsFile->findNext(Tokens::$commentTokens, ($opener + 1), $closer); $fixable = ($hasComment === false); diff --git a/Modernize/Tests/FunctionCalls/DirnameUnitTest.inc b/Modernize/Tests/FunctionCalls/DirnameUnitTest.inc index 30e67bb1..688f1d95 100644 --- a/Modernize/Tests/FunctionCalls/DirnameUnitTest.inc +++ b/Modernize/Tests/FunctionCalls/DirnameUnitTest.inc @@ -48,7 +48,7 @@ $path = dirname(\dirname(__DIR__) . '/file.php'); // Nested dirname() call not s * These should be flagged for use of dirname(__FILE__). */ $path = dirname(__FILE__); -$path = \dirname ( __FILE__ , ) ; // Includes trailing comma. +$path = \dirname ( __file__ , ) ; // Includes trailing comma. $path = DirName(__FILE__ /* todo: replace with __DIR__ */); // Not auto-fixable. @@ -70,7 +70,7 @@ $path = dirname(path: __FILE__, levels: 1); $path = dirname(levels: 3, path: __FILE__); // phpcs:ignore Modernize.FunctionCalls.Dirname.Nested -- Only apply __DIR__ fix, not $levels. -$path = dirname(dirname(dirname(dirname(__FILE__)))); +$path = dirname(dirname(dirname(dirname(__file__)))); /* @@ -129,7 +129,7 @@ $path = dirname( levels: 2, path: dirname( path: dirname( - path: __FILE__ + path: __file__ ), levels: 3, ) diff --git a/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php b/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php index f0d1f21c..692243bd 100644 --- a/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php +++ b/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php @@ -13,7 +13,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Utils\ObjectDeclarations; /** * Standardize the modifier keyword order for class declarations. @@ -90,37 +90,7 @@ public function register() */ public function process(File $phpcsFile, $stackPtr) { - /* - * Note to self: This can be switched to use the `ObjectDeclarations::getClassProperties()` - * method once that has been adjusted to return stackPtrs as well. - */ - $tokens = $phpcsFile->getTokens(); - $valid = Collections::classModifierKeywords() + Tokens::$emptyTokens; - $classProp = [ - 'abstract_token' => false, - 'final_token' => false, - 'readonly_token' => false, - ]; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (isset($valid[$tokens[$i]['code']]) === false) { - break; - } - - switch ($tokens[$i]['code']) { - case \T_ABSTRACT: - $classProp['abstract_token'] = $i; - break; - - case \T_FINAL: - $classProp['final_token'] = $i; - break; - - case \T_READONLY: - $classProp['readonly_token'] = $i; - break; - } - } + $classProp = ObjectDeclarations::getClassProperties($phpcsFile, $stackPtr); if ($classProp['readonly_token'] === false || ($classProp['final_token'] === false && $classProp['abstract_token'] === false) diff --git a/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php b/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php index 8299dc0d..e779bd22 100644 --- a/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php +++ b/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php @@ -13,6 +13,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Scopes; /** @@ -65,17 +66,6 @@ final class ModifierKeywordOrderSniff implements Sniff */ public $order = self::FINAL_VISIBILITY; - /** - * Tokens which can be constant modifier keywords. - * - * @since 1.0.0 - * - * @var array - */ - private $constantModifierKeywords = [ - \T_FINAL => \T_FINAL, - ]; - /** * Returns an array of tokens this test wants to listen for. * @@ -85,9 +75,6 @@ final class ModifierKeywordOrderSniff implements Sniff */ public function register() { - // Add the visibility keywords to the constant modifier keywords. - $this->constantModifierKeywords += Tokens::$scopeModifiers; - return [\T_CONST]; } @@ -108,12 +95,8 @@ public function process(File $phpcsFile, $stackPtr) return; } - /* - * Note to self: This can be switched to use the `Collections::constantModifierKeywords()` - * method as of the next version of PHPCSUtils. - */ $tokens = $phpcsFile->getTokens(); - $valid = $this->constantModifierKeywords + Tokens::$emptyTokens; + $valid = Collections::constantModifierKeywords() + Tokens::$emptyTokens; $finalPtr = false; $visibilityPtr = false; diff --git a/Universal/Sniffs/Lists/DisallowShortListSyntaxSniff.php b/Universal/Sniffs/Lists/DisallowShortListSyntaxSniff.php index 56087409..e57d243e 100644 --- a/Universal/Sniffs/Lists/DisallowShortListSyntaxSniff.php +++ b/Universal/Sniffs/Lists/DisallowShortListSyntaxSniff.php @@ -39,10 +39,7 @@ final class DisallowShortListSyntaxSniff implements Sniff */ public function register() { - $targets = Collections::shortArrayListOpenTokensBC(); - $targets[\T_LIST] = \T_LIST; // Only for recording metrics. - - return $targets; + return Collections::listOpenTokensBC(); } /** diff --git a/composer.json b/composer.json index 8d5d0f56..6a8cb018 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,7 @@ "require" : { "php" : ">=5.4", "squizlabs/php_codesniffer" : "^3.7.1", - "dealerdirect/phpcodesniffer-composer-installer" : "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7", - "phpcsstandards/phpcsutils" : "^1.0 || dev-develop" + "phpcsstandards/phpcsutils" : "^1.0" }, "require-dev" : { "php-parallel-lint/php-parallel-lint": "^1.3.2", @@ -38,8 +37,6 @@ "dev-develop": "1.x-dev" } }, - "minimum-stability": "dev", - "prefer-stable": true, "scripts" : { "lint": [ "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . --show-deprecated -e php --exclude vendor --exclude .git"