diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..28391bc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,89 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + name: PHP ${{ matrix.php-version }} Test + runs-on: ubuntu-22.04 + permissions: + contents: read + + strategy: + fail-fast: false + matrix: + php-version: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: dom, mbstring + coverage: ${{ matrix.php-version == '8.3' && 'xdebug' || 'none' }} + + - name: Validate composer.json + run: composer validate + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.json') }} + restore-keys: | + ${{ runner.os }}-php-${{ matrix.php-version }}- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction + + - name: Run test suite + run: vendor/bin/phpunit ${{ matrix.php-version == '8.3' && '--coverage-clover=coverage.xml' || '' }} + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + if: matrix.php-version == '8.3' + with: + files: ./coverage.xml + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + + code-quality: + name: Code Quality + runs-on: ubuntu-22.04 + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: dom, mbstring + tools: cs2pr + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-php-8.3-${{ hashFiles('**/composer.json') }} + restore-keys: | + ${{ runner.os }}-php-8.3- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction + + - name: Run PHP_CodeSniffer + shell: bash + run: set -o pipefail && vendor/bin/phpcs --report=checkstyle | cs2pr diff --git a/.gitignore b/.gitignore index 183037e..2a681d8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ vendor/ /demo/bower_components /demo/node_modules .DS_Store -.idea \ No newline at end of file +.idea +.phpunit.result.cache +coverage.xml \ No newline at end of file diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 04a587e..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,138 +0,0 @@ -imports: - - php -tools: - js_hint: true - php_code_sniffer: true - -build: - nodes: - analysis: - tests: - override: - - phpcs-run - tests: - tests: - override: - - - command: 'vendor/bin/phpunit --coverage-clover=code-coverage-file' - coverage: - file: 'code-coverage-file' - format: 'php-clover' - -filter: - excluded_paths: - - tests/* -checks: - php: - uppercase_constants: true - unused_variables: true - unreachable_code: true - unused_methods: true - sql_injection_vulnerabilities: true - spacing_of_function_arguments: true - spacing_around_non_conditional_operators: true - spacing_around_conditional_operators: true - too_many_arguments: true - return_doc_comments: true - require_scope_for_properties: true - require_scope_for_methods: true - require_braces_around_control_structures: true - psr2_control_structure_declaration: true - code_rating: true - duplication: true - variable_existence: true - useless_calls: true - use_statement_alias_conflict: true - unused_properties: true - unused_parameters: true - security_vulnerabilities: true - precedence_mistakes: true - precedence_in_conditions: true - parameter_non_unique: true - no_property_on_interface: true - no_non_implemented_abstract_methods: true - deprecated_code_usage: true - closure_use_not_conflicting: true - closure_use_modifiable: true - avoid_useless_overridden_methods: true - avoid_conflicting_incrementers: true - assignment_of_null_return: true - verify_access_scope_valid: true - symfony_request_injection: true - simplify_boolean_return: true - side_effects_or_types: true - scope_indentation: - spaces_per_level: '4' - return_doc_comment_if_not_inferrable: true - remove_trailing_whitespace: true - remove_php_closing_tag: true - remove_extra_empty_lines: true - psr2_switch_declaration: true - psr2_class_declaration: true - property_assignments: true - properties_in_camelcaps: true - phpunit_assertions: true - php5_style_constructor: true - parameters_in_camelcaps: true - parameter_doc_comments: true - param_doc_comment_if_not_inferrable: true - overriding_private_members: true - one_class_per_file: true - optional_parameters_at_the_end: true - non_commented_empty_catch_block: true - no_unnecessary_if: true - no_unnecessary_function_call_in_for_loop: true - no_space_inside_cast_operator: true - no_space_before_semicolon: true - no_space_around_object_operator: true - no_short_open_tag: true - no_short_method_names: - minimum: '3' - no_goto: true - no_global_keyword: true - no_exit: true - no_eval: true - no_long_variable_names: - maximum: '40' - no_empty_statements: true - no_error_suppression: true - no_else_if_statements: true - no_duplicate_arguments: true - no_debug_code: true - no_commented_out_code: true - missing_arguments: true - method_calls_on_non_object: true - lowercase_php_keywords: true - lowercase_basic_constants: true - instanceof_class_exists: true - function_in_camel_caps: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: false - order_alphabetically: true - fix_identation_4spaces: true - ensure_lower_case_builtin_functions: true - fix_doc_comments: true - avoid_unnecessary_concatenation: true - avoid_entity_manager_injection: true - avoid_closing_tag: true - require_php_tag_first: true - line_length: - max_length: '120' - function_body_start_on_new_line: true - fix_php_opening_tag: true - fix_linefeed: true - classes_in_camel_caps: true - catch_class_exists: true - avoid_tab_indentation: true - avoid_superglobals: true - avoid_multiple_statements_on_same_line: true - avoid_length_functions_in_loops: true - avoid_duplicate_types: true - avoid_corrupting_byteorder_marks: true - argument_type_checks: true - no_underscore_prefix_in_properties: true - no_underscore_prefix_in_methods: true - blank_line_after_namespace_declaration: true - verify_argument_usable_as_reference: true diff --git a/README.md b/README.md index 357c573..132f0e7 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ php-htmldiff ============ -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/caxy/php-htmldiff/badges/quality-score.png?b=master)][badge_score] -[![Build Status](https://scrutinizer-ci.com/g/caxy/php-htmldiff/badges/build.png?b=master)][badge_status] -[![Code Coverage](https://scrutinizer-ci.com/g/caxy/php-htmldiff/badges/coverage.png?b=master)][badge_coverage] +[![CI](https://github.com/caxy/php-htmldiff/workflows/CI/badge.svg)][badge_ci] +[![Code Coverage](https://codecov.io/gh/caxy/php-htmldiff/branch/master/graph/badge.svg)][badge_coverage] [![Packagist](https://img.shields.io/packagist/dt/caxy/php-htmldiff.svg)][badge_packagist] [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/caxy/php-htmldiff.svg)][badge_resolve] [![Percentage of issues still open](http://isitmaintained.com/badge/open/caxy/php-htmldiff.svg)][badge_issues] @@ -213,9 +212,8 @@ php-htmldiff is available under [GNU General Public License, version 2][gnu]. Se * Add documentation on alternative htmldiff engines and perhaps some comparisons -[badge_score]: https://scrutinizer-ci.com/g/caxy/php-htmldiff/?branch=master -[badge_status]: https://scrutinizer-ci.com/g/caxy/php-htmldiff/build-status/master -[badge_coverage]: https://scrutinizer-ci.com/g/caxy/php-htmldiff/?branch=master +[badge_ci]: https://github.com/caxy/php-htmldiff/actions/workflows/ci.yml +[badge_coverage]: https://codecov.io/gh/caxy/php-htmldiff [badge_packagist]: https://packagist.org/packages/caxy/php-htmldiff [badge_resolve]: http://isitmaintained.com/project/caxy/php-htmldiff "Average time to resolve an issue" [badge_issues]: http://isitmaintained.com/project/caxy/php-htmldiff "Percentage of issues still open" diff --git a/composer.json b/composer.json index 9e7c0fd..2891b43 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ }, "require-dev": { "phpunit/phpunit": "~9.0", - "doctrine/cache": "~1.0" + "doctrine/cache": "~1.0", + "squizlabs/php_codesniffer": "^3.7" }, "suggest": { "doctrine/cache": "Used for caching the calculated diffs using a Doctrine Cache Provider" diff --git a/lib/Caxy/HtmlDiff/HtmlDiff.php b/lib/Caxy/HtmlDiff/HtmlDiff.php index 9f13658..1a387f7 100644 --- a/lib/Caxy/HtmlDiff/HtmlDiff.php +++ b/lib/Caxy/HtmlDiff/HtmlDiff.php @@ -243,13 +243,13 @@ protected function isClosingIsolatedDiffTag($item, $currentIsolatedDiffTag = nul protected function performOperation($operation) { switch ($operation->action) { - case 'equal' : + case 'equal': $this->processEqualOperation($operation); break; - case 'delete' : + case 'delete': $this->processDeleteOperation($operation, 'diffdel'); break; - case 'insert' : + case 'insert': $this->processInsertOperation($operation, 'diffins'); break; case 'replace': @@ -334,7 +334,7 @@ protected function diffIsolatedPlaceholder($operation, $pos, $placeholder, $stri } elseif ($this->isImagePlaceholder($placeholder)) { return $this->diffElementsByAttribute($oldText, $newText, 'src', 'img'); } elseif ($this->isPicturePlaceholder($placeholder)) { - return $this->diffPicture($oldText, $newText); + return $this->diffPicture($oldText, $newText); } return $this->diffElements($oldText, $newText, $stripWrappingTags); @@ -401,7 +401,8 @@ protected function diffTables($oldText, $newText) * * @return string */ - protected function diffPicture($oldText, $newText) { + protected function diffPicture($oldText, $newText) + { if ($oldText !== $newText) { return sprintf( '%s%s', @@ -410,7 +411,7 @@ protected function diffPicture($oldText, $newText) { ); } return $this->diffElements($oldText, $newText); - } + } protected function diffElementsByAttribute($oldText, $newText, $attribute, $element) { @@ -567,8 +568,7 @@ protected function insertTag($tag, $cssClass, &$words) $workTag = $this->extractConsecutiveWords($words, 'tag'); - if ( - isset($workTag[0]) === true && + if (isset($workTag[0]) === true && $this->isOpeningTag($workTag[0]) === true && $this->isClosingTag($workTag[0]) === false ) { @@ -848,8 +848,7 @@ protected function oldTextIsOnlyWhitespace(int $startingAtWord, int $wordCount) $this->resetCache = false; } - if ( - $cache !== null && + if ($cache !== null && $lastWordCount === $wordCount && $lastStartingWordOffset === $startingAtWord ) { // Hit diff --git a/lib/Caxy/HtmlDiff/ListDiffLines.php b/lib/Caxy/HtmlDiff/ListDiffLines.php index cfc68c7..df000bf 100644 --- a/lib/Caxy/HtmlDiff/ListDiffLines.php +++ b/lib/Caxy/HtmlDiff/ListDiffLines.php @@ -390,8 +390,7 @@ private function getInnerHtml(DOMNode $node) : string { $bufferDom = new DOMDocument('1.0', 'UTF-8'); - foreach($node->childNodes as $childNode) - { + foreach ($node->childNodes as $childNode) { $bufferDom->appendChild($bufferDom->importNode($childNode, true)); } diff --git a/phpcs.xml b/phpcs.xml index 0f24ab8..d563b5c 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -2,5 +2,7 @@ ./lib ./tests - + + + diff --git a/tests/Caxy/Tests/HtmlDiff/HtmlFileIterator.php b/tests/Caxy/Tests/HtmlDiff/HtmlFileIterator.php index 7173b3f..428ca24 100644 --- a/tests/Caxy/Tests/HtmlDiff/HtmlFileIterator.php +++ b/tests/Caxy/Tests/HtmlDiff/HtmlFileIterator.php @@ -62,7 +62,6 @@ protected function loadHtmlFile($key) $filename = $this->files[$key]; if (!isset($this->loadedDiffs[$filename])) { - $html = file_get_contents($filename); $this->loadedDiffs[$filename] = [ @@ -71,7 +70,6 @@ protected function loadHtmlFile($key) $this->parseTagContent('expected', $html), $this->configXmlToArray($this->parseTagContent('options', $html)), ]; - } return $this->loadedDiffs[$filename]; diff --git a/tests/Caxy/Tests/HtmlDiff/Performance/PerformanceTest.php b/tests/Caxy/Tests/HtmlDiff/Performance/PerformanceTest.php index 1f4e3b7..146ddd6 100644 --- a/tests/Caxy/Tests/HtmlDiff/Performance/PerformanceTest.php +++ b/tests/Caxy/Tests/HtmlDiff/Performance/PerformanceTest.php @@ -19,7 +19,8 @@ public function testParagraphPerformance() $diff = new HtmlDiff( file_get_contents(self::FIXTURE_PATH . 'paragraphs.html'), file_get_contents(self::FIXTURE_PATH . 'paragraphs_changed.html'), - 'UTF-8', array() + 'UTF-8', + array() ); $output = $diff->build();