diff --git a/.github/assets/github-actions-pr.png b/.github/assets/github-actions-pr.png new file mode 100644 index 00000000..03b1de2b Binary files /dev/null and b/.github/assets/github-actions-pr.png differ diff --git a/.github/assets/github-actions-termintal.png b/.github/assets/github-actions-termintal.png new file mode 100644 index 00000000..261a736a Binary files /dev/null and b/.github/assets/github-actions-termintal.png differ diff --git a/Makefile b/Makefile index 1254fc7f..d620b0aa 100644 --- a/Makefile +++ b/Makefile @@ -24,11 +24,13 @@ build: ##@Project Install all 3rd party dependencies @make build-phar @rm -f `pwd`/ci-report-converter + build-install: ##@Project Install all 3rd party dependencies as prod $(call title,"Install/Update all 3rd party dependencies as prod") @composer install --no-dev --no-progress --no-interaction --no-suggest @rm -f `pwd`/ci-report-converter + update: ##@Project Install/Update all 3rd party dependencies @echo "Composer flags: $(JBZOO_COMPOSER_UPDATE_FLAGS)" @composer update $(JBZOO_COMPOSER_UPDATE_FLAGS) diff --git a/README.md b/README.md index 113a93bd..767dd5d0 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,266 @@ # JBZoo / Csv-Blueprint -[![CI](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/main.yml?query=branch%3Amaster) [![Coverage Status](https://coveralls.io/repos/github/JBZoo/Csv-Blueprint/badge.svg?branch=master)](https://coveralls.io/github/JBZoo/Csv-Blueprint?branch=master) [![Psalm Coverage](https://shepherd.dev/github/JBZoo/Csv-Blueprint/coverage.svg)](https://shepherd.dev/github/JBZoo/Csv-Blueprint) [![Psalm Level](https://shepherd.dev/github/JBZoo/Csv-Blueprint/level.svg)](https://shepherd.dev/github/JBZoo/Csv-Blueprint) [![CodeFactor](https://www.codefactor.io/repository/github/jbzoo/csv-blueprint/badge)](https://www.codefactor.io/repository/github/jbzoo/csv-blueprint/issues) +[![CI](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/main.yml?query=branch%3Amaster) [![CI](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/demo.yml/badge.svg?branch=master)](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/demo.yml?query=branch%3Amaster) [![CI](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/release-docker.yml/badge.svg?branch=master)](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/release-docker.yml?query=branch%3Amaster) [![Coverage Status](https://coveralls.io/repos/github/JBZoo/Csv-Blueprint/badge.svg?branch=master)](https://coveralls.io/github/JBZoo/Csv-Blueprint?branch=master) [![Psalm Coverage](https://shepherd.dev/github/JBZoo/Csv-Blueprint/coverage.svg)](https://shepherd.dev/github/JBZoo/Csv-Blueprint) [![Psalm Level](https://shepherd.dev/github/JBZoo/Csv-Blueprint/level.svg)](https://shepherd.dev/github/JBZoo/Csv-Blueprint) [![CodeFactor](https://www.codefactor.io/repository/github/jbzoo/csv-blueprint/badge)](https://www.codefactor.io/repository/github/jbzoo/csv-blueprint/issues) [![Stable Version](https://poser.pugx.org/jbzoo/csv-blueprint/version)](https://packagist.org/packages/jbzoo/csv-blueprint/) [![Total Downloads](https://poser.pugx.org/jbzoo/csv-blueprint/downloads)](https://packagist.org/packages/jbzoo/csv-blueprint/stats) [![Docker Pulls](https://img.shields.io/docker/pulls/jbzoo/csv-blueprint.svg)](https://hub.docker.com/r/jbzoo/csv-blueprint) [![Dependents](https://poser.pugx.org/jbzoo/csv-blueprint/dependents)](https://packagist.org/packages/jbzoo/csv-blueprint/dependents?order_by=downloads) [![GitHub License](https://img.shields.io/github/license/jbzoo/csv-blueprint)](https://github.com/JBZoo/Csv-Blueprint/blob/master/LICENSE) +* [Introduction](#introduction) +* [Why validate CSV files in CI?](#why-validate-csv-files-in-ci) +* [Features](#features) +* [Live Demo](#live-demo) +* [Usage](#usage) + * [As GitHub Action](#as-github-action) + * [As Docker container](#as-docker-container) + * [As PHP binary](#as-php-binary) + * [As PHP project](#as-php-project) + * [Schema Definition](#schema-definition) + * [Schema file examples](#schema-file-examples) +* [Coming soon](#coming-soon) +* [Disadvantages?](#disadvantages) +* [Interesting fact](#interesting-fact) +* [Unit tests and check code style](#unit-tests-and-check-code-style) +* [License](#license) +* [See Also](#see-also) -### Installing + +## Introduction + +The JBZoo/Csv-Blueprint tool is a powerful and flexible utility designed for validating CSV files against +a predefined schema specified in YAML format. With the capability to run both locally and in Docker environments, +JBZoo/Csv-Blueprint is an ideal choice for integrating into CI/CD pipelines, such as GitHub Actions, +to ensure the integrity of CSV data in your projects. + + +## Why validate CSV files in CI? + +Validating CSV files at the Continuous Integration (CI) level within a repository is crucial for several reasons in data engineering: + +* **Data Quality Assurance**: Ensures that the data meets predefined standards and formats before it's used in applications or analytics, preventing data corruption and inconsistency issues. +* **Early Detection of Errors**: Identifies problems with data submissions or changes early in the development process, reducing the time and effort required for troubleshooting and fixes. +* **Automated Data Governance**: Enforces data governance policies automatically, ensuring that all data complies with regulatory and business rules. +* **Streamlined Data Integration**: Facilitates smoother data integration processes by ensuring that the data being ingested from different sources adheres to the expected schema, minimizing integration errors. +* **Collaboration and Transparency**: Helps teams collaborate more effectively by providing clear standards for data formats and validation rules, leading to more transparent and predictable data handling practices. + +Integrating CSV validation into CI processes promotes higher data integrity, reliability, and operational efficiency in data engineering projects. + + +## Features + +* **Schema-based Validation**: Define the structure and rules for your CSV files in an intuitive [YAML format](schema-examples/full.yml), enabling precise validation against your data's expected format. +* **Flexible Configuration**: Support for custom delimiters, quote characters, enclosures, and encoding settings to handle a wide range of CSV formats. +* **Comprehensive Rule Set**: Includes a broad set of validation rules, such as non-empty fields, exact values, regular expressions, numeric constraints, date formats, and more, catering to various data validation needs. +* **Docker Support**: Easily integrate into any workflow with Docker, providing a seamless experience for development, testing, and production environments. +* **GitHub Actions Integration**: Automate CSV validation in your CI/CD pipeline, enhancing the quality control of your data in pull requests and deployments. +* **Various ways to report:** issues that can be easily integrated with GithHub, Gitlab, TeamCity, etc. The default output is a human-readable table. [See Live Demo](https://github.com/JBZoo/Csv-Blueprint). + + +## Live Demo + +* As a live demonstration of how the tool works you can take a look at the super minimal repository - [JBZoo/Csv-Blueprint-Demo](https://github.com/JBZoo/Csv-Blueprint). Feel free to fork it and play with the tool. +* You can see more complex examples and different ways of reporting by looking at the [last Demo pipeline](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/demo.yml?query=branch%3Amaster) (please open the logs). There you'll find the basic ways to get started. And also the `All Report Types` (left sidebar) link with the different report types. + +**See also** +* [.github/workflows/demo.yml](.github/workflows/demo.yml) +* [demo_invalid.yml](tests/schemas/demo_invalid.yml) +* [demo_valid.yml](tests/schemas/demo_valid.yml) +* [demo.csv](tests/fixtures/demo.csv) + + +## Usage + +Also see demo in the [GitHub Actions](https://github.com/JBZoo/Csv-Blueprint/actions/workflows/demo.yml) file. + + +### As GitHub Action + +```yml + - name: Validate CSV file + uses: jbzoo/csv-blueprint@master + with: + csv: tests/fixtures/demo.csv + schema: tests/schemas/demo_invalid.yml + output: table # Optional. Default is "github" +``` +**Note**. Output format for GitHub Actions is `github` by default. [GitHub Actions friendly](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message). + +This allows you to see bugs in the GitHub interface at the PR level. +That is, the error will be shown in a specific place in the CSV file right in diff of your Pull Requests! + +![GitHub Actions - PR](.github/assets/github-actions-pr.png) + +
+ Click to see example in GitHub Actions terminal + + ![GitHub Actions - Terminal](.github/assets/github-actions-termintal.png) + +
+ + +### As Docker container +Ensure you have Docker installed on your machine. ```sh -composer require jbzoo/csv-blueprint +# Pull the Docker image +docker pull jbzoo/csv-blueprint + +# Run the tool inside Docker +docker run --rm \ + --workdir=/parent-host \ + -v .:/parent-host \ + jbzoo/csv-blueprint \ + validate:csv \ + --csv=./tests/fixtures/demo.csv \ + --schema=./tests/schemas/demo_invalid.yml ``` -### Usage +### As PHP binary +Ensure you have PHP installed on your machine. -As Docker container: +**Status: WIP**. It's not released yet. But you can build it from source. See manual above and `./build//csv-blueprint.phar` file. ```sh -@docker run --rm \ - -v `pwd`:/parent-host \ - jbzoo/csv-blueprint \ - validate:csv \ - --csv=/parent-host/tests/fixtures/demo.csv \ - --schema=/parent-host/tests/schemas/demo_invalid.yml \ - --ansi +wget https://github.com/JBZoo/Csv-Blueprint/releases/latest/download/csv-blueprint.phar +chmod +x ./csv-blueprint.phar +./csv-blueprint.phar validate:csv \ + --csv=./tests/fixtures/demo.csv \ + --schema=./tests/schemas/demo_invalid.yml ``` -### Schema file examples +### As PHP project +Ensure you have PHP installed on your machine. +Then, you can use the following commands to build from source and run the tool. + +```sh +git clone git@github.com:jbzoo/csv-blueprint.git csv-blueprint +cd csv-blueprint +make build +./csv-blueprint validate:csv \ + --csv=./tests/fixtures/demo.csv \ + --schema=./tests/schemas/demo_invalid.yml +``` + + +### CLI Help Message + +Here you can see all available options and commands. +Tool uses [JBZoo/Cli](https://github.com/JBZoo/Cli) package for the CLI interface. +So there are options here for all occasions. + + +``` +./csv-blueprint validate:csv --help + + +Description: + Validate CSV file by rule + +Usage: + validate:csv [options] + +Options: + -c, --csv=CSV CSV filepath to validate. + -s, --schema=SCHEMA Schema rule filepath. + -o, --output=OUTPUT Report output format. Available options: text, table, github, gitlab, teamcity, junit [default: "table"] + --no-progress Disable progress bar animation for logs. It will be used only for text output format. + --mute-errors Mute any sort of errors. So exit code will be always "0" (if it's possible). + It has major priority then --non-zero-on-error. It's on your own risk! + --stdout-only For any errors messages application will use StdOut instead of StdErr. It's on your own risk! + --non-zero-on-error None-zero exit code on any StdErr message. + --timestamp Show timestamp at the beginning of each message.It will be used only for text output format. + --profile Display timing and memory usage information. + --output-mode=OUTPUT-MODE Output format. Available options: + text - Default text output format, userfriendly and easy to read. + cron - Shortcut for crontab. It's basically focused on human-readable logs output. + It's combination of --timestamp --profile --stdout-only --no-progress -vv. + logstash - Logstash output format, for integration with ELK stack. + [default: "text"] + --cron Alias for --output-mode=cron. Deprecated! + -h, --help Display help for the given command. When no command is given display help for the list command + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi|--no-ansi Force (or disable --no-ansi) ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +``` + + +### Output Example + +As a result of the validation process, you will receive a human-readable table with a list of errors found in the CSV file. By defualt, the output format is a table, but you can choose from a variety of formats, such as text, GitHub, GitLab, TeamCity, JUnit, and more. For example, the following output is generated using the "table" format. + +**Notes** +* Output format for GitHub Actions is `github` by default. +* Tools uses [JBZoo/CI-Report-Converter](https://github.com/JBZoo/CI-Report-Converter) as SDK to convert reports to different formats. So you can easily integrate it with any CI system. -
- Click to see: YAML format (with comment) + +Default output format is `table`: + +``` +CSV : ./tests/fixtures/demo.csv +Schema : ./tests/schemas/demo_invalid.yml ++------+------------------+--------------+-- demo.csv -------------------------------------------+ +| Line | id:Column | Rule | Message | ++------+------------------+--------------+-------------------------------------------------------+ +| 1 | 1: | csv.header | Property "name" is not defined in schema: | +| | | | "./tests/schemas/demo_invalid.yml" | +| 5 | 2:Float | max | Value "74605.944" is greater than "74605" | +| 5 | 4:Favorite color | allow_values | Value "blue" is not allowed. Allowed values: ["red", | +| | | | "green", "Blue"] | +| 6 | 0:Name | min_length | Value "Carl" (legth: 4) is too short. Min length is 5 | +| 6 | 3:Birthday | min_date | Value "1955-05-14" is less than the minimum date | +| | | | "1955-05-15T00:00:00.000+00:00" | +| 8 | 3:Birthday | min_date | Value "1955-05-14" is less than the minimum date | +| | | | "1955-05-15T00:00:00.000+00:00" | +| 9 | 3:Birthday | max_date | Value "2010-07-20" is more than the maximum date | +| | | | "2009-01-01T00:00:00.000+00:00" | +| 11 | 0:Name | min_length | Value "Lois" (legth: 4) is too short. Min length is 5 | +| 11 | 4:Favorite color | allow_values | Value "blue" is not allowed. Allowed values: ["red", | +| | | | "green", "Blue"] | ++------+------------------+--------------+-- demo.csv -------------------------------------------+ + +CSV file is not valid! Found 9 errors. + +``` + + +### Schema Definition +Define your CSV validation schema in a YAML file. + +This example defines a simple schema for a CSV file with a header row, specifying that the `id` column must not be empty and must contain integer values. +Also, it checks that the `name` column has a minimum length of 3 characters. + +```yml +csv: + delimiter: ; + +columns: + - name: id + rules: + not_empty: true + is_int: true + + - name: name + rules: + min_length: 3 + +``` + +In the [example Yml file](schema-examples/full.yml) you can find a detailed description of all features. +It's also covered by tests, so it's always up-to-date. + +**Important notes** +* I have deliberately refused typing of columns (like `type: integer`) and replaced them with rules, +which can be combined in any sequence and completely at your discretion. +This gives you great flexibility when validating CSV files. +* All fields (unless explicitly stated otherwise) are optional, and you can choose not to declare them. Up to you. +* You are always free to add your option anywhere (except the `rules` list) and it will be ignored. I find it convenient for additional integrations and customization. + + +### Schema file examples ```yml # It's a full example of the CSV schema file in YAML format. @@ -93,8 +322,6 @@ columns: ``` -
-
Click to see: JSON Format @@ -212,13 +439,96 @@ return [
-## Unit tests and check code style +## Coming soon + +It's random ideas and plans. No orderings and deadlines. But batch processing is the priority #1. + +* [ ] Filename pattern validation with regex (like "all files in the folder should be in the format `/^[\d]{4}-[\d]{2}-[\d]{2}\.csv$/`"). +* [ ] CSV/Schema file discovery in the folder with regex filename pattern (like `glob(./**/dir/*.csv)`). +* [ ] If option `--csv` is a folder, then validate all files in the folder. +* [ ] If option `--csv` is not specified, then the STDIN is used. To build a pipeline in Unix-like systems. +* [ ] If option `--schema` is not specified, then validate only super base level things (like "is it a CSV file?"). +* [ ] Agregate rules (like "at least one of the fields should be not empty" or "all values must be unique"). +* [ ] Create CSV files based on the schema (like "create 1000 rows with random data based on schema and rules"). +* [ ] Checking multiple CSV files in one schema. Batch processing. +* [ ] Using multiple schemas for one csv file. Batch processing. +* [ ] Parallel validation of really-really large files (1GB+ ?). I know you have them and not so much memory. +* [ ] Parallel validation of multiple files at once. +* [ ] Benchmarks as part of the CI process and Readme. It's important to know how much time the validation process takes. +* [ ] Inheritance of schemas, rules and columns. Define parent schema and override some rules in the child schemas. Make it DRY and easy to maintain. +* [ ] More output formats (like JSON, XML, etc). Any ideas? +* [ ] Complex rules (like "if field `A` is not empty, then field `B` should be not empty too"). +* [ ] Input encoding detection + `BOM` (right now it's experimental). It works but not so accurate... UTF-8/16/32 is the best choice for now. +* [ ] Extending with custom rules and custom output formats. Plugins? +* [ ] More examples and documentation. + +PS. [There is a file](tests/schemas/example_full.yml) with my ideas and imagination. +I'm not sure if I will implement all of them. But I will try to do my best. + + +## Disadvantages? + +* Yeah-yeah. I know it's not the fastest tool in the world. But it's not the slowest either. +* Yeah-yeah. I know it's PHP (not a Python, Go). PHP is not the best language for such tasks. +* Yeah-yeah. It looks like a standalone binary. +* Yeah-yeah. I know you can't use as Python SDK as part of pipeline. + +But... it's not a problem for most cases. And it solves the problem of validating CSV files in CI. 👍 + +The utility is made to just pick up and use and not think about how it works internally. +Moreover, everything is covered as strictly as possible by tests, strict typing of variables + `~7` linters and static analyzers (max level of rules). +Also, if you look, you'll see that any PR goes through about `~30` different checks on GitHub Actions (matrix of PHP versions and mods). +Since I don't know under what conditions the code will be used, everything I can think of is covered. The wonderful world of Open Source. + +So... as strictly as possible in today's PHP world. I think it works as expected. + + +## Interesting fact + +I think I've set a personal record. +The first version was written from scratch in about 3 days (with really frequent breaks to take care of 4 month baby). +I'm looking at the first commit and the very first git tag. I'd say over the weekend, in my spare time on my personal laptop. +Well... AI I only used for this Readme file because I'm not very good at English. 🤔 + +I seem to be typing fast and I had really great inspiration. I hope my wife doesn't divorce me. 😅 + + +## Contributing +If you have any ideas or suggestions, feel free to open an issue or create a pull request. + ```sh -make update -make test-all +# Fork the repo and build project +git clone git@github.com:jbzoo/csv-blueprint.git ./jbzoo-csv-blueprint +cd ./jbzoo-csv-blueprint +make build + +# Make your local changes + +# Autofix code style +make test-phpcsfixer-fix + +# Run all tests and check code style +make test +make codestyle + +# Create your pull request and check all tests in CI (Github Actions) +# ??? +# Profit! ``` ### License -MIT +[MIT License](LICENSE): It's like free pizza - enjoy it, share it, just don't sell it as your own. And remember, no warranty for stomach aches! 😅 + + +## See Also + +- [CI-Report-Converter](https://github.com/JBZoo/CI-Report-Converter) - It converts different error reporting standards for popular CI systems. +- [Composer-Diff](https://github.com/JBZoo/Composer-Diff) - See what packages have changed after `composer update`. +- [Composer-Graph](https://github.com/JBZoo/Composer-Graph) - Dependency graph visualization of `composer.json` based on [Mermaid JS](https://mermaid.js.org/). +- [Mermaid-PHP](https://github.com/JBZoo/Mermaid-PHP) - Generate diagrams and flowcharts with the help of the [mermaid](https://mermaid.js.org/) script language. +- [Utils](https://github.com/JBZoo/Utils) - Collection of useful PHP functions, mini-classes, and snippets for every day. +- [Image](https://github.com/JBZoo/Image) - Package provides object-oriented way to manipulate with images as simple as possible. +- [Data](https://github.com/JBZoo/Data) - Extended implementation of ArrayObject. Use Yml/PHP/JSON/INI files as config. Forget about arrays. +- [Retry](https://github.com/JBZoo/Retry) - Tiny PHP library providing retry/backoff functionality with strategies and jitter. diff --git a/action.yml b/action.yml index c278afc7..1bd76e5c 100644 --- a/action.yml +++ b/action.yml @@ -10,7 +10,7 @@ # @see https://github.com/JBZoo/Csv-Blueprint # -name: 'CSV Validator' +name: 'CSV Validator by schemas' description: 'Strict and flexible schema-based CSV file validation with the ability to report as GitHub Annotations in your PRs.' author: 'Denis Smetannikov ' @@ -41,4 +41,5 @@ runs: - ${{ inputs.schema }} - '--output' - ${{ inputs.output }} + - '--ansi' - '-vvv' diff --git a/src/Csv/CsvFile.php b/src/Csv/CsvFile.php index d39e35ac..dfd9cbd9 100644 --- a/src/Csv/CsvFile.php +++ b/src/Csv/CsvFile.php @@ -43,7 +43,7 @@ public function __construct(string $csvFilename, null|array|string $csvSchemaFil public function getCsvFilename(): string { - return \pathinfo((string)\realpath($this->csvFilename), \PATHINFO_BASENAME); + return $this->csvFilename; } public function getCsvStructure(): ParseConfig diff --git a/src/Validators/ErrorSuite.php b/src/Validators/ErrorSuite.php index 35055d6b..3e2f5838 100644 --- a/src/Validators/ErrorSuite.php +++ b/src/Validators/ErrorSuite.php @@ -135,8 +135,8 @@ private function renderTable(): string { $buffer = new BufferedOutput(); $table = (new Table($buffer)) - ->setHeaderTitle($this->csvFilename) - ->setFooterTitle($this->csvFilename) + ->setHeaderTitle($this->getTestcaseName()) + ->setFooterTitle($this->getTestcaseName()) ->setHeaders(['Line', 'id:Column', 'Rule', 'Message']) ->setColumnMaxWidth(0, 10) ->setColumnMaxWidth(1, 20) @@ -154,7 +154,7 @@ private function renderTable(): string private function prepareSourceSuite(): SourceSuite { - $suite = new SourceSuite($this->csvFilename); + $suite = new SourceSuite($this->getTestcaseName()); foreach ($this->errors as $error) { $caseName = $error->getRuleCode() . ' at column ' . $error->getColumnName(); @@ -166,4 +166,9 @@ private function prepareSourceSuite(): SourceSuite return $suite; } + + private function getTestcaseName(): string + { + return \pathinfo((string)\realpath((string)$this->csvFilename), \PATHINFO_BASENAME); + } } diff --git a/tests/Blueprint/CsvReaderTest.php b/tests/Blueprint/CsvReaderTest.php index 4291b685..c80ef60f 100644 --- a/tests/Blueprint/CsvReaderTest.php +++ b/tests/Blueprint/CsvReaderTest.php @@ -32,7 +32,7 @@ final class CsvReaderTest extends PHPUnit public function testReadCsvFileWithoutHeader(): void { $csv = new CsvFile(self::CSV_SIMPLE_NO_HEADER, self::SCHEMA_SIMPLE_NO_HEADER); - isSame('simple_no_header.csv', $csv->getCsvFilename()); + isSame(self::CSV_SIMPLE_NO_HEADER, $csv->getCsvFilename()); isSame([], $csv->getHeader()); @@ -50,7 +50,7 @@ public function testReadCsvFileWithoutHeader(): void public function testReadCsvFileWithHeader(): void { $csv = new CsvFile(self::CSV_SIMPLE_HEADER, self::SCHEMA_SIMPLE_HEADER); - isSame('simple_header.csv', $csv->getCsvFilename()); + isSame(self::CSV_SIMPLE_HEADER, $csv->getCsvFilename()); isSame(['seq', 'bool', 'exact'], $csv->getHeader()); diff --git a/tests/Blueprint/MiscTest.php b/tests/Blueprint/MiscTest.php index 09a91b88..1003aed7 100644 --- a/tests/Blueprint/MiscTest.php +++ b/tests/Blueprint/MiscTest.php @@ -145,7 +145,9 @@ private function testCheckExampleInReadme( $tmpl = \implode("\n", ["```{$type}", $filepath, '```']); } - $tmpl = $this->getSpoiler("Click to see: {$title}", $tmpl); + if ($type !== 'yml') { + $tmpl = $this->getSpoiler("Click to see: {$title}", $tmpl); + } isFileContains($tmpl, PROJECT_ROOT . '/README.md'); } diff --git a/tests/Blueprint/ValidatorTest.php b/tests/Blueprint/ValidatorTest.php index d3ac054f..bbb617fa 100644 --- a/tests/Blueprint/ValidatorTest.php +++ b/tests/Blueprint/ValidatorTest.php @@ -461,12 +461,13 @@ public function testRenderTable(): void public function testRenderTeamCity(): void { - $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); - $out = $csv->validate()->render(ErrorSuite::RENDER_TEAMCITY); + $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $out = $csv->validate()->render(ErrorSuite::RENDER_TEAMCITY); + $path = self::CSV_SIMPLE_HEADER; isContain("##teamcity[testCount count='2' ", $out); isContain("##teamcity[testSuiteStarted name='simple_header.csv' ", $out); - isContain("##teamcity[testStarted name='min at column 0:seq' locationHint='php_qn://simple_header.csv'", $out); + isContain("##teamcity[testStarted name='min at column 0:seq' locationHint='php_qn://{$path}'", $out); isContain("##teamcity[testFinished name='min at column 0:seq' timestamp", $out); isContain('Value "1" is less than "3"', $out); isContain('Value "2" is less than "3"', $out); @@ -475,12 +476,13 @@ public function testRenderTeamCity(): void public function testRenderGithub(): void { - $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $path = self::CSV_SIMPLE_HEADER; isSame( \implode("\n", [ - '::error file=simple_header.csv,line=2::min at column 0:seq%0AValue "1" is less than "3"', + "::error file={$path},line=2::min at column 0:seq%0AValue \"1\" is less than \"3\"", '', - '::error file=simple_header.csv,line=3::min at column 0:seq%0AValue "2" is less than "3"', + "::error file={$path},line=3::min at column 0:seq%0AValue \"2\" is less than \"3\"", '', ]), $csv->validate()->render(ErrorSuite::RENDER_GITHUB), @@ -489,44 +491,50 @@ public function testRenderGithub(): void public function testRenderGitlab(): void { - $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $path = self::CSV_SIMPLE_HEADER; + + $cleanJson = json($csv->validate()->render(ErrorSuite::RENDER_GITLAB))->getArrayCopy(); + unset($cleanJson[0]['fingerprint'], $cleanJson[1]['fingerprint']); + isSame( [ [ 'description' => "min at column 0:seq\nValue \"1\" is less than \"3\"", - 'fingerprint' => 'ec0612c9f1610d440b558fff51bbceed086a0212cdeb14d79d09c8a9bd108487', - 'severity' => 'major', - 'location' => [ - 'path' => 'simple_header.csv', + // 'fingerprint' => '2c2639beb20e2e9ea13a414ce91865522f6e1885abcf1f99ada44de007cdb01f', + 'severity' => 'major', + 'location' => [ + 'path' => $path, 'lines' => ['begin' => 2], ], ], [ 'description' => "min at column 0:seq\nValue \"2\" is less than \"3\"", - 'fingerprint' => '51f82750d029c395dec5f2f5c1c4eb841e43c1ea6b8ece9ee31126a3e22620cb', - 'severity' => 'major', - 'location' => [ - 'path' => 'simple_header.csv', + // 'fingerprint' => '0cda6e2df28be9033542ab504e315d070951a206446eb7005d2060d44cfa0e45', + 'severity' => 'major', + 'location' => [ + 'path' => $path, 'lines' => ['begin' => 3], ], ], ], - json($csv->validate()->render(ErrorSuite::RENDER_GITLAB))->getArrayCopy(), + $cleanJson, ); } public function testRenderJUnit(): void { - $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $csv = new CsvFile(self::CSV_SIMPLE_HEADER, $this->getRule('seq', 'min', 3)); + $path = self::CSV_SIMPLE_HEADER; isSame( \implode("\n", [ '', '', ' ', - ' ', + " ", ' Value "1" is less than "3"', ' ', - ' ', + " ", ' Value "2" is less than "3"', ' ', ' ', diff --git a/tests/CsvBlueprintPackageTest.php b/tests/CsvBlueprintPackageTest.php index ae6e4ec0..8cfb817d 100644 --- a/tests/CsvBlueprintPackageTest.php +++ b/tests/CsvBlueprintPackageTest.php @@ -20,10 +20,93 @@ final class CsvBlueprintPackageTest extends \JBZoo\Codestyle\PHPUnit\AbstractPac { protected string $packageName = 'Csv-Blueprint'; + protected array $params = [ + // Packagist + 'packagist_latest_stable_version' => true, + 'packagist_latest_unstable_version' => true, + 'packagist_license' => true, + 'packagist_version' => true, + + 'packagist_dependents' => true, + 'packagist_suggesters' => true, + + 'packagist_downloads_total' => true, + 'packagist_downloads_daily' => true, + 'packagist_downloads_monthly' => true, + + 'packagist_composerlock' => true, + 'packagist_gitattributes' => true, + + 'github_issues' => true, + 'github_license' => true, + 'github_forks' => true, + 'github_stars' => true, + 'github_actions' => true, + + 'github_actions_demo' => true, + 'github_actions_release_docker' => true, + + 'docker_pulls' => true, + + 'psalm_coverage' => true, + 'psalm_level' => true, + 'codacy' => true, + 'codefactor' => true, + 'sonarcloud' => true, + 'coveralls' => true, + 'circle_ci' => true, + ]; + + protected array $badgesTemplate = [ + 'github_actions', + 'github_actions_demo', + 'github_actions_release_docker', + 'docker_build', + 'codecov', + 'coveralls', + 'psalm_coverage', + 'psalm_level', + 'codefactor', + 'scrutinizer', + '__BR__', + 'packagist_latest_stable_version', + 'packagist_downloads_total', + 'docker_pulls', + 'packagist_dependents', + 'visitors', + 'github_license', + ]; + protected function setUp(): void { - $this->params['docker_pulls'] = true; + $this->excludePaths[] = 'assets'; parent::setUp(); } + + protected function checkBadgeGithubActionsDemo(): ?string + { + $path = 'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/actions/workflows'; + + return $this->getPreparedBadge( + $this->getBadge( + 'CI', + $path . '/demo.yml/badge.svg?branch=master', + $path . '/demo.yml?query=branch%3Amaster', + ), + ); + } + + protected function checkBadgeGithubActionsReleaseDocker(): ?string + { + $path = 'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/actions/workflows'; + + return $this->getPreparedBadge( + $this->getBadge( + 'CI', + $path . '/release-docker.yml/badge.svg?branch=master', + $path . '/release-docker.yml?query=branch%3Amaster', + ), + ); + } } diff --git a/tests/fixtures/demo.csv b/tests/fixtures/demo.csv index 451ae8a8..a0850f0f 100644 --- a/tests/fixtures/demo.csv +++ b/tests/fixtures/demo.csv @@ -1,5 +1,5 @@ Name,City,Float,Birthday,Favorite color -Clyde,Rivsikgo,4825.1856,2000-01-01,red +Clyde,Rivsikgo,4825.1856,2000-01-01,green Elsie,Vonavka,03.6544,2000-12-01,green Derek,Sarefunaw,-177.9088,2000-01-31,green Dylan,Wufolu,74605.944,1998-02-28,blue @@ -8,4 +8,4 @@ Landon,Mojebol,123.64,1989-05-15,red Olive,Pebiogu,0,1955-05-14,green Willie,Sowaah,0.001,2010-07-20,red Derrick,Rakufag,42,1990-09-10,green -Lois,Mofninle,-19366059127.6032,1988-08-24,blue +Lois,Mofninle,-19366059127.6032,1988-08-24,green diff --git a/tests/schemas/demo_invalid.yml b/tests/schemas/demo_invalid.yml index 6a39d179..fe8e396e 100644 --- a/tests/schemas/demo_invalid.yml +++ b/tests/schemas/demo_invalid.yml @@ -10,6 +10,8 @@ # @see https://github.com/JBZoo/Csv-Blueprint # +# This schema is invalid because does not match the CSV file (tests/fixtures/demo.csv). + columns: - name: Name rules: diff --git a/tests/schemas/demo_valid.yml b/tests/schemas/demo_valid.yml index a90fea5d..3dd44214 100644 --- a/tests/schemas/demo_valid.yml +++ b/tests/schemas/demo_valid.yml @@ -10,6 +10,8 @@ # @see https://github.com/JBZoo/Csv-Blueprint # +# This schema is valid because match the CSV file (tests/fixtures/demo.csv) perfectly. + columns: - name: Name rules: