├── .gitignore
├── .rmt.yml
├── .travis.php.ini
├── .travis.yml
├── CHANGELOG
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── UPGRADE-3.0.md
├── bin
└── qa-tools
├── box.release.json
├── box.test.json
├── build
├── release
│ ├── .gitkeep
│ └── qa-tools.phar.pubkey
└── test
│ └── .gitkeep
├── composer.json
├── composer.lock
├── couscous.yml
├── docs
├── couscous
│ └── template
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── css
│ │ ├── bootstrap.min.css
│ │ ├── highlight.forest-light.css
│ │ └── main.css
│ │ ├── default.twig
│ │ └── js
│ │ └── highlight.min.js
├── development.md
├── development
│ ├── configuration-process.md
│ ├── task-development.md
│ ├── tool-development.md
│ ├── writing-documentation.md
│ └── writing-system-tests.md
├── phar.md
├── release-process.md
├── reporting-a-bug.md
└── ubiquitous-language.md
├── installer.php
├── phpmd.xml
├── phpunit.xml
├── qa-tools.json
├── ruleset.xml
├── src
├── Composer
│ ├── BoxDownloaderScriptHandler.php
│ └── BuildPharScriptHandler.php
├── Core
│ ├── Application
│ │ ├── Application.php
│ │ ├── Basedir.php
│ │ ├── Command
│ │ │ ├── ConfigureCommand.php
│ │ │ ├── PreCommitCommand.php
│ │ │ ├── PrePushCommand.php
│ │ │ └── SelfUpdateCommand.php
│ │ ├── Compiler
│ │ │ ├── RegisterConfiguratorsCompilerPass.php
│ │ │ └── RegisterTaskExecutorsCompilerPass.php
│ │ └── ContainerLoader.php
│ ├── Assert
│ │ └── Assertion.php
│ ├── Build
│ │ ├── Build.php
│ │ ├── Snippet.php
│ │ └── Tool.php
│ ├── Composer
│ │ ├── CliComposerProject.php
│ │ ├── CliComposerProjectFactory.php
│ │ ├── Configuration.php
│ │ ├── Package.php
│ │ ├── PackageName.php
│ │ ├── PackageSet.php
│ │ ├── PackageVersionConstraint.php
│ │ ├── Project.php
│ │ ├── ProjectFactory.php
│ │ ├── RequireCache.php
│ │ └── RuntimeException.php
│ ├── Configuration
│ │ ├── Configuration.php
│ │ ├── ConfigurationRepository.php
│ │ ├── ConfigurationService.php
│ │ ├── FileConfigurationRepository.php
│ │ ├── InMemoryConfigurationRepository.php
│ │ ├── InMemoryTaskDirectory.php
│ │ ├── InMemoryTaskDirectoryFactory.php
│ │ ├── MemorizingInterviewer.php
│ │ ├── ProjectConfigurator.php
│ │ ├── QuestionId.php
│ │ ├── TaskDirectory.php
│ │ ├── TaskDirectoryFactory.php
│ │ ├── TaskHelperSet.php
│ │ └── ToolConfigurator.php
│ ├── Configurator
│ │ ├── Configurator.php
│ │ ├── ConfiguratorList.php
│ │ └── ConfiguratorRepository.php
│ ├── Exception
│ │ ├── InvalidAnswerGivenException.php
│ │ ├── InvalidArgumentException.php
│ │ ├── LogicException.php
│ │ └── RuntimeException.php
│ ├── GitHook
│ │ ├── GitHookInstaller.php
│ │ └── files
│ │ │ ├── pre-commit
│ │ │ └── pre-push
│ ├── IO
│ │ ├── Cli
│ │ │ ├── ConsoleQuestionFactory.php
│ │ │ ├── ConsoleQuestionFormatter.php
│ │ │ ├── Interviewer.php
│ │ │ ├── InterviewerFactory.php
│ │ │ └── Validator
│ │ │ │ ├── TextualAnswerValidator.php
│ │ │ │ └── YesOrNoAnswerValidator.php
│ │ └── File
│ │ │ ├── FileHandler.php
│ │ │ └── FilesystemFileHandler.php
│ ├── Interviewer
│ │ ├── Answer
│ │ │ ├── Answer.php
│ │ │ ├── AnswerFactory.php
│ │ │ ├── Choices.php
│ │ │ ├── NoDefaultAnswer.php
│ │ │ ├── TextualAnswer.php
│ │ │ └── YesOrNoAnswer.php
│ │ ├── AutomatedResponseInterviewer.php
│ │ ├── Interviewer.php
│ │ ├── Question
│ │ │ ├── ListChoiceQuestion.php
│ │ │ ├── MultipleChoiceQuestion.php
│ │ │ ├── Question.php
│ │ │ ├── QuestionFactory.php
│ │ │ ├── TextualQuestion.php
│ │ │ └── YesOrNoQuestion.php
│ │ └── ScopedInterviewer.php
│ ├── Project
│ │ ├── Directory.php
│ │ ├── Project.php
│ │ ├── ProjectType.php
│ │ └── ProjectTypeSet.php
│ ├── Resources
│ │ ├── config
│ │ │ ├── config.yml
│ │ │ ├── services.yml
│ │ │ └── task_executors.yml
│ │ └── templates
│ │ │ └── build.xml.twig
│ ├── Task
│ │ ├── AddAntBuildTask.php
│ │ ├── Executor
│ │ │ ├── AddBuildTaskExecutor.php
│ │ │ ├── ArrayExecutorCollection.php
│ │ │ ├── Executor.php
│ │ │ ├── ExecutorCollection.php
│ │ │ ├── InstallComposerDevDependencyTaskExecutor.php
│ │ │ ├── Sigints.php
│ │ │ ├── TaskDirectoryExecutor.php
│ │ │ ├── TransactionalTaskDirectoryExecutor.php
│ │ │ └── WriteFileTaskExecutor.php
│ │ ├── InstallComposerDevDependencyTask.php
│ │ ├── Task.php
│ │ ├── TaskList.php
│ │ └── WriteFileTask.php
│ ├── Templating
│ │ ├── Escape.php
│ │ ├── TemplateEngine.php
│ │ └── TwigFactory.php
│ └── Tool
│ │ ├── AbstractTool.php
│ │ └── Tool.php
├── PharUpdater
│ └── Strategy
│ │ └── GitHubReleasesApiStrategy.php
└── Tool
│ ├── Behat
│ ├── Behat.php
│ ├── Configurator
│ │ ├── BehatConfigurator.php
│ │ └── DrupalBehatConfigurator.php
│ └── Resources
│ │ ├── config
│ │ └── configurators.yml
│ │ └── templates
│ │ ├── FeatureContext.php.twig
│ │ ├── ant-build.xml.twig
│ │ ├── behat.yml
│ │ └── drupal
│ │ ├── FeatureContext.php.twig
│ │ └── behat.yml
│ ├── PhpCs
│ ├── Configurator
│ │ ├── PhpCsConfigurator.php
│ │ ├── PhpCsDrupal7Configurator.php
│ │ └── PhpCsDrupal8Configurator.php
│ ├── PhpCs.php
│ └── Resources
│ │ ├── config
│ │ └── configurators.yml
│ │ └── templates
│ │ ├── ant-build.xml.twig
│ │ ├── ruleset-reference.xml.twig
│ │ ├── ruleset.xml.twig
│ │ ├── snippet-ignore-function-comments-in-tests.xml.twig
│ │ └── snippet-line-length.xml.twig
│ ├── PhpMd
│ ├── Configurator
│ │ ├── DrupalPhpMdConfigurator.php
│ │ └── PhpMdConfigurator.php
│ ├── PhpMd.php
│ └── Resources
│ │ ├── config
│ │ └── configurators.yml
│ │ └── templates
│ │ ├── ant-build.xml.twig
│ │ └── phpmd-default.xml.twig
│ ├── PhpParallelLint
│ ├── Configurator
│ │ ├── DrupalPhpParallelLintConfigurator.php
│ │ └── PhpParallelLintConfigurator.php
│ ├── PhpParallelLint.php
│ └── Resources
│ │ ├── config
│ │ └── configurators.yml
│ │ └── templates
│ │ ├── ant-diff.xml.twig
│ │ └── ant-full.xml.twig
│ ├── PhpUnit
│ ├── Configurator
│ │ ├── Drupal8PhpUnitConfigurator.php
│ │ └── PhpUnitConfigurator.php
│ ├── PhpUnit.php
│ └── Resources
│ │ ├── config
│ │ └── configurators.yml
│ │ └── templates
│ │ ├── ant-build.xml.twig
│ │ ├── drupal8
│ │ ├── bootstrap.php.twig
│ │ └── phpunit.xml.twig
│ │ ├── phpunit.default.xml.twig
│ │ └── phpunit.symfony.xml.twig
│ └── SensioLabsSecurityChecker
│ ├── Configurator
│ └── SecurityCheckerConfigurator.php
│ ├── Resources
│ ├── config
│ │ └── configurators.yml
│ └── templates
│ │ └── ant-build.xml.twig
│ └── SensioLabsSecurityChecker.php
├── tests
├── MockeryTestCase.php
├── bootstrap.php
├── composer
│ ├── Composer.php
│ └── packages
│ │ ├── behat
│ │ └── behat
│ │ │ └── composer.json
│ │ ├── drupal
│ │ ├── coder7
│ │ │ └── composer.json
│ │ ├── coder8
│ │ │ └── composer.json
│ │ └── drupal-extension
│ │ │ └── composer.json
│ │ ├── escapestudios
│ │ └── symfony2-coding-standard
│ │ │ └── composer.json
│ │ ├── jakub-onderka
│ │ └── php-parallel-lint
│ │ │ └── composer.json
│ │ ├── phpmd
│ │ └── phpmd
│ │ │ └── composer.json
│ │ ├── phpunit
│ │ └── phpunit
│ │ │ └── composer.json
│ │ ├── sensiolabs
│ │ └── security-checker
│ │ │ └── composer.json
│ │ └── squizlabs
│ │ └── php_codesniffer
│ │ └── composer.json
├── integration
│ ├── .gitkeep
│ ├── ContainerTestCase.php
│ ├── Core
│ │ ├── Composer
│ │ │ └── CliComposerProjectTest.php
│ │ ├── IO
│ │ │ └── File
│ │ │ │ └── FilesystemFileHandlerTest.php
│ │ ├── Task
│ │ │ └── Executor
│ │ │ │ └── SigintsTest.php
│ │ ├── Templating
│ │ │ ├── TemplateEngineTest.php
│ │ │ └── templates
│ │ │ │ └── non-existent-variable.twig
│ │ └── Tool
│ │ │ ├── AbstractToolTest.php
│ │ │ └── Hammer
│ │ │ ├── Hammer.php
│ │ │ └── Resources
│ │ │ └── .gitkeep
│ └── Installer
│ │ └── InstallerTest.php
├── security
│ ├── .gitkeep
│ └── verify-readme-installer-hash
├── system
│ ├── Composer.php
│ ├── SystemTest.php
│ ├── assert.php
│ ├── harness.tcl
│ └── specs
│ │ ├── 000_can-configure-a-php-project.php
│ │ ├── 000_can-configure-a-php-project.tcl
│ │ ├── 003_can-configure-a-symfony-project.php
│ │ ├── 003_can-configure-a-symfony-project.tcl
│ │ ├── 005_can-configure-a-drupal8-project.php
│ │ ├── 005_can-configure-a-drupal8-project.tcl
│ │ ├── 010_developer-need-not-reanswer-previously-answered-questions.php
│ │ ├── 010_developer-need-not-reanswer-previously-answered-questions.tcl
│ │ ├── 020_aborts-on-composer-dependency-conflict.php
│ │ ├── 020_aborts-on-composer-dependency-conflict.tcl
│ │ ├── 025_developer-need-not-reanswer-even-when-previous-run-failed.php
│ │ ├── 025_developer-need-not-reanswer-even-when-previous-run-failed_configure.tcl
│ │ ├── 025_developer-need-not-reanswer-even-when-previous-run-failed_reconfigure.tcl
│ │ ├── 030_aborts-when-config-cannot-be-written.php
│ │ ├── 030_aborts-when-config-cannot-be-written_setup.tcl
│ │ ├── 030_aborts-when-config-cannot-be-written_try-writing.tcl
│ │ ├── 040_offers_to_initialise_composer.php
│ │ ├── 040_offers_to_initialise_composer.tcl
│ │ ├── 050_can-install-git-pre-commit-hook.php
│ │ ├── 050_can-install-git-pre-commit-hook.tcl
│ │ ├── 055_asks-confirmation-before-overwriting-pre-commit-hook.php
│ │ ├── 055_asks-confirmation-before-overwriting-pre-commit-hook.tcl
│ │ ├── 060_can-install-git-pre-push-hook.php
│ │ ├── 060_can-install-git-pre-push-hook.tcl
│ │ ├── 065_asks-confirmation-before-overwriting-pre-push-hook.php
│ │ └── 065_asks-confirmation-before-overwriting-pre-push-hook.tcl
└── unit
│ ├── AddBuildTaskMatcher.php
│ ├── Core
│ ├── Application
│ │ └── Compiler
│ │ │ └── RegisterTaskExecutorsCompilerPassTest.php
│ ├── Assert
│ │ └── AssertionTest.php
│ ├── Composer
│ │ ├── PackageSetTest.php
│ │ ├── PackageTest.php
│ │ ├── PackageVersionConstraintTest.php
│ │ └── RequireCacheTest.php
│ ├── Configuration
│ │ ├── ConfiguratorRepositoryTest.php
│ │ ├── FakeConfigurator.php
│ │ ├── FileConfigurationRepositoryTest.php
│ │ ├── InMemoryConfigurationRepositoryTest.php
│ │ ├── InMemoryTaskDirectoryTest.php
│ │ └── TaskHelperSetTest.php
│ ├── GitHook
│ │ └── GitHookInstallerTest.php
│ ├── IO
│ │ ├── Cli
│ │ │ ├── ConsoleQuestionFactoryTest.php
│ │ │ ├── ConsoleQuestionFormatterTest.php
│ │ │ ├── InterviewerTest.php
│ │ │ └── Validator
│ │ │ │ ├── TextualAnswerValidatorTest.php
│ │ │ │ └── YesOrNoAnswerValidatorTest.php
│ │ └── File
│ │ │ └── FilesystemFileHandlerTest.php
│ ├── Interviewer
│ │ ├── Answer
│ │ │ ├── AnswerFactoryTest.php
│ │ │ ├── ChoicesTest.php
│ │ │ ├── NoDefaultAnswerTest.php
│ │ │ ├── TextualAnswerTest.php
│ │ │ └── YesOrNoAnswerTest.php
│ │ ├── AutomatedResponseInterviewerTest.php
│ │ └── Question
│ │ │ ├── ListChoiceQuestionTest.php
│ │ │ ├── MultipleChoiceQuestionTest.php
│ │ │ ├── QuestionFactoryTest.php
│ │ │ ├── TextualQuestionTest.php
│ │ │ └── YesOrNoQuestionTest.php
│ ├── MemorizingInterviewerTest.php
│ ├── Project
│ │ ├── DirectoryTest.php
│ │ ├── ProjectTypeSetTest.php
│ │ └── ProjectTypeTest.php
│ └── Task
│ │ ├── Executor
│ │ ├── AddBuildTaskExecutorTest.php
│ │ ├── ArrayExecutorCollectionTest.php
│ │ ├── InstallComposerDevDependencyTaskExecutorTest.php
│ │ ├── TransactionalTaskDirectoryExecutorTest.php
│ │ └── WriteFileTaskExecutorTest.php
│ │ ├── NoopTask.php
│ │ └── TaskListTest.php
│ ├── Diffing.php
│ ├── InstallComposerDevDependencyTaskMatcher.php
│ ├── Installer
│ └── InstallerTest.php
│ ├── PharUpdater
│ └── Strategy
│ │ ├── GitHubReleasesApiStrategyTest.php
│ │ ├── no-releases.json
│ │ ├── two-releases.json
│ │ ├── two-stable-releases-one-phar.json
│ │ └── two-stable-releases.json
│ ├── TestDataProvider.php
│ ├── Tool
│ ├── Behat
│ │ └── Configurator
│ │ │ ├── BehatConfiguratorTest.php
│ │ │ └── DrupalBehatConfiguratorTest.php
│ ├── PhpCs
│ │ └── Configurator
│ │ │ ├── PhpCsConfiguratorTest.php
│ │ │ ├── PhpCsDrupal7ConfiguratorTest.php
│ │ │ └── PhpCsDrupal8ConfiguratorTest.php
│ ├── PhpMd
│ │ └── Configurator
│ │ │ ├── DrupalPhpMdConfiguratorTest.php
│ │ │ └── PhpMdConfiguratorTest.php
│ ├── PhpParallelLint
│ │ └── Configurator
│ │ │ ├── DrupalPhpParallelLintConfiguratorTest.php
│ │ │ └── PhpParallelLintConfiguratorTest.php
│ ├── PhpUnit
│ │ └── Configurator
│ │ │ ├── Drupal8PhpUnitConfiguratorTest.php
│ │ │ └── PhpUnitConfiguratorTest.php
│ └── SensioLabsSecurityChecker
│ │ └── Configurator
│ │ └── SecurityCheckerConfiguratorTest.php
│ ├── ValueObject.php
│ └── WriteFileTaskMatcher.php
├── tools
├── build-phar.php
└── git
│ ├── pre-commit
│ ├── pre-commit-install
│ ├── pre-push
│ └── pre-push-install
└── var
├── cache
└── .gitkeep
└── composer
└── .gitignore
/.gitignore:
--------------------------------------------------------------------------------
1 | /.couscous/
2 | /build/test/qa-tools*
3 | /build/release/qa-tools*
4 | !/build/release/qa-tools.pubkey
5 | /vendor/
6 | /var/cache/*
7 | /bin/box
8 | /box.json
9 | /build.xml
10 | /signing-key-*.pem
11 |
--------------------------------------------------------------------------------
/.rmt.yml:
--------------------------------------------------------------------------------
1 | _default:
2 |
3 | # VCS CONFIG
4 | vcs: git
5 |
6 | # PREREQUISITES
7 | # Actions executed before any questions get asked to the user.
8 | # Custom action can be added by provided a relative path the the php script. Example:
9 | # - relative/path/to/your-own-sript.php
10 | prerequisites:
11 | working-copy-check: ~
12 | display-last-changes: ~
13 | composer-stability-check: ~
14 | tests-check: {command: make test, timeout: 120}
15 |
16 | # GENERAL CONFIG
17 | # Apply to all branches except the one from the 'branch-specific' section
18 | # Like prerequisites, you can add your own script. Example:
19 | # - relative/path/to/your-own-sript.php
20 | version-generator:
21 | semantic:
22 | allow-label: true
23 | version-persister:
24 | vcs-tag: # Release with VCS tag
25 | tag-prefix: "{branch-name}_" # Prefix any tag with the VCS branch name
26 | dump-commits: true
27 | pre-release-actions:
28 | changelog-update: # Update a CHANGELOG file before the release
29 | format: semantic
30 | vcs-commit: ~ # Commit the CHANGELOG
31 | post-release-actions:
32 | vcs-publish: # Publish the release to the VCS
33 | ask-confirmation: true
34 |
35 | # BRANCH SPECIFIC CONFIG
36 | # On master, we override the general config
37 | master:
38 | version-persister:
39 | vcs-tag:
40 | tag-prefix: '' # No more prefix for tags
41 |
--------------------------------------------------------------------------------
/.travis.php.ini:
--------------------------------------------------------------------------------
1 | date.timezone = "UTC"
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: php
3 | php:
4 | - 5.6
5 | - 7.0
6 | - 7.1
7 | - nightly
8 | matrix:
9 | fast_finish: true
10 | allow_failures:
11 | - php: nightly
12 | addons:
13 | apt:
14 | packages: [expect]
15 |
16 | cache:
17 | directories:
18 | - ~/.composer/cache/files/
19 |
20 | before_install:
21 | - phpenv config-add .travis.php.ini
22 |
23 | install:
24 | - composer install --prefer-dist
25 |
26 | script:
27 | - make test
28 |
29 | after_success:
30 | # Deploy documentation to gh-pages branch when Travis CI build against PHP 7.1 on master succeeds
31 | - GIT_NAME=TravisCI GIT_EMAIL=info@ibuildings.nl GH_REF=github.com/ibuildingsnl/qa-tools vendor/bin/couscous travis-auto-deploy --php-version=7.1
32 |
33 | branches:
34 | only: [master, develop]
35 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 |
2 | VERSION 3 STAND-ALONE QA TOOLS
3 | ============================================================
4 |
5 | Version 3.0 - Stand-alone QA Tools
6 | 17/03/2017 14:02 3.0.0-beta Internal beta release
7 | 24/02/2017 09:57 3.0.0-alpha2 Make installation and updating more robust
8 | 17/02/2017 14:23 3.0.0-alpha initial release
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Ibuildings
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/UPGRADE-3.0.md:
--------------------------------------------------------------------------------
1 | Upgrading from 2.x to 3.0
2 | =========================
3 |
4 | The third major release of QA Tools takes a whole different approach and requires you to reconfigure your project's quality assurance tools. If this is acceptable, follow these steps to remove QA Tools 2.x from your project:
5 |
6 | * Remove all artifacts related to QA Tools 2.x: `qa-tools.json`, `.jshintrc`, `.travis.php.ini`, `.travis.yml`, `behat.dev.yml`, `behat.yml`, `build-pre-commit.xml`, `build.xml`, `phpcs.xml`, `phpmd-pre-commit.xml`, `phpmd.xml`, `phpunit.xml`, `pre-commit`.
7 | * Remove `ibuildings/qa-tools` from your Composer dependencies by running `composer remove ibuildings/qa-tools`. *(Note: if you run Composer <1.0 add the `--update-with-dependencies` flag to also remove QA Tools 2's dependencies.)*
8 | * Install QA Tools 3 by following the [installation instructions](./README.md#Installation)
9 | * Reconfigure QA Tools by calling `/path/to/qa-tools.phar configure` in your project directory.
10 |
--------------------------------------------------------------------------------
/bin/qa-tools:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | addCommands([
18 | new ConfigureCommand(),
19 | new SelfUpdateCommand(),
20 | new PreCommitCommand(),
21 | new PrePushCommand(),
22 | ]);
23 | $application->boot();
24 |
25 | exit($application->run());
26 |
--------------------------------------------------------------------------------
/box.release.json:
--------------------------------------------------------------------------------
1 | {
2 | "algorithm": "OPENSSL",
3 | "chmod": "0755",
4 | "compression": "GZ",
5 | "directories": [
6 | "var/cache",
7 | "src"
8 | ],
9 | "files": [
10 | "LICENSE"
11 | ],
12 | "finder": [
13 | {
14 | "name": "*.php",
15 | "exclude": [],
16 | "in": "vendor"
17 | }
18 | ],
19 | "git-version": "package_version",
20 | "intercept": false,
21 | "key": "signing-key-release.pem",
22 | "main": "bin/qa-tools",
23 | "output": "build/release/qa-tools.phar",
24 | "stub": true
25 | }
26 |
--------------------------------------------------------------------------------
/box.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "algorithm": "OPENSSL",
3 | "chmod": "0755",
4 | "compression": "GZ",
5 | "directories": [
6 | "var/cache",
7 | "src"
8 | ],
9 | "files": [
10 | "LICENSE"
11 | ],
12 | "finder": [
13 | {
14 | "name": "*.php",
15 | "exclude": [],
16 | "in": "vendor"
17 | }
18 | ],
19 | "git-version": "package_version",
20 | "intercept": false,
21 | "key": "signing-key-test.pem",
22 | "main": "bin/qa-tools",
23 | "output": "build/test/qa-tools.phar",
24 | "stub": true
25 | }
26 |
--------------------------------------------------------------------------------
/build/release/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ibuildingsnl/qa-tools/0c4999a74c55b03a826e1c881f75ee3fba6329f7/build/release/.gitkeep
--------------------------------------------------------------------------------
/build/release/qa-tools.phar.pubkey:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEA2QbIDqX9CmKDUpXXrKEo
3 | UiYQiR7h0Cx6iKh0LlogqAuVmm/qFH27LbMErzTNKhd9HLlq361J1JTgCKNMM79S
4 | MgQhm+WUU4Zdzd3MsmHtDuGyv6bd92kTuTx4csm5Jnh3je4vy4kTOKQ/0cQ9/f4y
5 | 926sL2up0akrcVhqTzXYxM9oEEPIrEky4CFgsXw5RtNSYqUiwerPV4c2uojQjznh
6 | 0qQEAqH252z2xJB45FlrMMDaK2eBiBKYcsaLpKORJtQJGDuOCl5tSst+nUHoB/Sz
7 | IjFY2dzBF4Yt8vGN0alxlqFYonnKtnD7ifz6pnya5+oGt47IQznrNm0DB7zq0anv
8 | 2b1gP7NBuqG/7sbvaCHqG8REridqXK/maOm/YBy82QaoqC9UW1K8Gz/W3khUMHTZ
9 | cv3qwKVJIOs73Clrh4oRxnds4UHGhLxANtiLzrD7U+eJQaZ8ecGh3L8ZOFeounsv
10 | YSLyqGxoqHNslBfmdmZupoWQLG4VzIWCR0ZcNfso7YPOsaJbJGUenC/s0ZjcYeWR
11 | WJUnYWTeY6n3OHxh2v/OO5BAGsrJFqkpTNMxhDkb+gTMw9AVMIlhIYvBmD6UIwz7
12 | 7pWAfPLgXggx+i7BzxeSq+pQNYdAwO04w4P7UpKEWQUjVfsPfABaLQK8E6kMJpN+
13 | EuwPcyFixgMDULX2c/QYO6ndcYDMW4qTLzRrv94OGy/WZMaihQoAe23TGB7PuJxb
14 | v/Aklr1203wNA0HYvuK3U2j7K7JlSVIn85NKKSRbE8yeR6No0We8ztbHSaakZFUD
15 | SJObFEtJ2JgA4hIs+XP+w4CSAB5fWQ0UjPMW6pwQNG5cop6Tgid+2a15xg9hQeQL
16 | 4LPKCRxX3qJDG0nMVtFrtpwQSWngZ72Cn2dotqfnm7XN2QgsxCFUK2JkiKHFGj9C
17 | HCY4R6D468/8KIqjAZGyYIUwX6JuA8RJnB7sZ70R5lsdB6pMrVqDpNF471umZ/+g
18 | aEb06j1bKh6I/66Cl9dCVFIhW6I11WQqFcQY+t1annIzDuZWzuH5TGqEuaA7ayaS
19 | No9g9v8bevKvcs3icq8QcIhYFcOtC+ATLTeZ4OrubOmzistFFsSk47NuWtcqSvbB
20 | jkjQFRRHozjXWhJz2z8szZpm3yxCYKpG5IZ+sKFXabo5M3lQZa4HgAomkhtdSgqh
21 | oC9ui6YzVpUlxFFUuNEogPevFH4sL4p98GeY4jb5ma9juNu8mGnDuZtjCSe3JEUM
22 | 8IrUn+eTp5K7w1xYTMnHgaSYjv+HI2R163uAiAEL5g/zu+Aounn414Q4ntRv1t2f
23 | 75c55erX/UMFApw5qDcbfu4BFIi2tEv8+om+pItBVaf7/LIMoQIOmF+L1IV0p1C+
24 | KQIDAQAB
25 | -----END PUBLIC KEY-----
26 |
--------------------------------------------------------------------------------
/build/test/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ibuildingsnl/qa-tools/0c4999a74c55b03a826e1c881f75ee3fba6329f7/build/test/.gitkeep
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ibuildings/qa-tools",
3 | "autoload": {
4 | "psr-4": {
5 | "Ibuildings\\QaTools\\" : "src/"
6 | }
7 | },
8 | "autoload-dev": {
9 | "psr-4": {
10 | "Ibuildings\\QaTools\\UnitTest\\": ["tests/unit"],
11 | "Ibuildings\\QaTools\\IntegrationTest\\": ["tests/integration"],
12 | "Ibuildings\\QaTools\\SystemTest\\": ["tests/system"],
13 | "Ibuildings\\QaTools\\ComposerTest\\": ["tests/composer"],
14 | "Ibuildings\\QaTools\\Test\\": ["tests"]
15 | },
16 | "files": ["tests/system/assert.php"]
17 | },
18 | "scripts": {
19 | "post-install-cmd": [
20 | "Ibuildings\\QaTools\\Composer\\BoxDownloaderScriptHandler::downloadBoxPhar"
21 | ],
22 | "build": [
23 | "Ibuildings\\QaTools\\Composer\\BuildPharScriptHandler::buildPhar"
24 | ]
25 | },
26 | "require": {
27 | "php": "^5.6|^7.0",
28 | "ext-pcntl": "*",
29 | "beberlei/assert": "^2.5",
30 | "composer/semver": "^1.4",
31 | "guzzlehttp/guzzle": "^6.2",
32 | "padraic/phar-updater": "^1.0",
33 | "psr/log": "^1.0",
34 | "symfony/config": "^3.2",
35 | "symfony/console": "^3.2",
36 | "symfony/dependency-injection": "^3.2",
37 | "symfony/process": "^3.2",
38 | "symfony/yaml": "^3.2",
39 | "twig/twig": "^1.24",
40 | "zendframework/zend-json": "^3.0"
41 | },
42 | "require-dev": {
43 | "ext-posix": "*",
44 | "composer/composer": "^1.2",
45 | "couscous/couscous": "^1.5",
46 | "jakub-onderka/php-console-highlighter": "^0.3.2",
47 | "jakub-onderka/php-parallel-lint": "^0.9.2",
48 | "liip/rmt": "^1.2.5",
49 | "mockery/mockery": "^0.9.4",
50 | "phpmd/phpmd": "^2.0",
51 | "phpunit/phpunit": "^5.7",
52 | "sebastian/diff": "^1.4",
53 | "sebastian/exporter": "^2",
54 | "sensiolabs/security-checker": "^3.0",
55 | "squizlabs/php_codesniffer": "^2.7",
56 | "symfony/filesystem": "^3.2"
57 | },
58 | "config": {
59 | "sort-packages": true
60 | },
61 | "extra": {
62 | "qa-tools-box-source": "https://github.com/box-project/box2/releases/download/2.7.5/box-2.7.5.phar",
63 | "qa-tools-box-install-path": "./bin/box",
64 | "qa-tools-box-sha-sum": "77561a72b84880572bc6d3ad3b36a905c42b68ba"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/couscous.yml:
--------------------------------------------------------------------------------
1 | baseUrl: https://ibuildingsnl.github.io/qa-tools
2 | title: Ibuildings QA Tools
3 | github:
4 | user: ibuildingsnl
5 | repo: qa-tools
6 |
7 | template:
8 | directory: docs/couscous/template
9 |
10 | menu:
11 | items:
12 | home:
13 | text: Ibuildings QA Tools
14 | relativeUrl: ""
15 | github:
16 | text: GitHub
17 | absoluteUrl: https://github.com/ibuildingsnl/qa-tools
18 | contributing-guidelines:
19 | text: Contributing guidelines
20 | relativeUrl: contributing.html
21 | development:
22 | text: Development
23 | relativeUrl: docs/development.html
24 | items:
25 | configuration-process:
26 | text: Configuration process
27 | relativeUrl: docs/development/configuration-process.html
28 | task-development:
29 | text: Task development
30 | relativeUrl: docs/development/task-development.html
31 | tool-development:
32 | text: Tool development
33 | relativeUrl: docs/development/tool-development.html
34 | writing-documentation:
35 | text: Writing documentation
36 | relativeUrl: docs/development/writing-documentation.html
37 | writing-system-tests:
38 | text: Writing system tests
39 | relativeUrl: docs/development/writing-system-tests.html
40 | phar:
41 | text: Phar
42 | relativeUrl: docs/phar.html
43 | release-process:
44 | text: Release process
45 | relativeUrl: docs/release-process.html
46 | reporting-a-bug:
47 | text: Reporting a bug
48 | relativeUrl: docs/reporting-a-bug.html
49 | ubiquitous-language:
50 | text: Ubiquitous language
51 | relativeUrl: docs/ubiquitous-language.html
52 |
--------------------------------------------------------------------------------
/docs/couscous/template/.gitignore:
--------------------------------------------------------------------------------
1 | /.couscous/
2 |
--------------------------------------------------------------------------------
/docs/couscous/template/README.md:
--------------------------------------------------------------------------------
1 | # Couscous template
2 |
3 | Based off https://github.com/CouscousPHP/Template-Light.
4 |
5 | ## Configuration
6 |
7 | Here are all the variables you can set in your `couscous.yml`:
8 |
9 | ```yaml
10 | # Base URL of the published website
11 | baseUrl: http://username.github.io/project
12 |
13 | # Used to link to the GitHub project
14 | github:
15 | user: myself
16 | repo: my-project
17 |
18 | title: My project
19 |
20 | # The left menu bar
21 | menu:
22 | items:
23 | home:
24 | text: Home page
25 | # You can use relative urls
26 | relativeUrl: doc/faq.html
27 | # You can add subitems
28 | items:
29 | text: Subitem
30 | relativeUrl: sub/item.html
31 | foo:
32 | text: Another link
33 | # Or absolute urls
34 | absoluteUrl: https://example.com
35 | ```
36 |
37 | Note that the menu items can also contain HTML:
38 |
39 | ```yaml
40 | home:
41 | text: " Home page"
42 | relativeUrl: doc/faq.html
43 | ```
44 |
--------------------------------------------------------------------------------
/docs/couscous/template/css/highlight.forest-light.css:
--------------------------------------------------------------------------------
1 | .hljs-comment,.hljs-quote{color:#766e6b}.hljs-variable,.hljs-template-variable,.hljs-attribute,.hljs-tag,.hljs-name,.hljs-regexp,.hljs-link,.hljs-name,.hljs-selector-id,.hljs-selector-class{color:#f22c40}.hljs-number,.hljs-meta,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params{color:#df5320}.hljs-string,.hljs-symbol,.hljs-bullet{color:#7b9726}.hljs-title,.hljs-section{color:#407ee7}.hljs-keyword,.hljs-selector-tag{color:#6666ea}.hljs{display:block;overflow-x:auto;background:#f1efee;color:#68615e;padding:0.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
2 |
--------------------------------------------------------------------------------
/docs/couscous/template/css/main.css:
--------------------------------------------------------------------------------
1 | html {
2 | position: relative;
3 | min-height: 100%;
4 | }
5 | body {
6 | font-size: 19px;
7 | }
8 |
9 | main {
10 | margin-top: 40px;
11 | }
12 |
13 | nav .nav .nav {
14 | margin-left: 1em;
15 | }
16 |
17 | section {
18 | margin-bottom: 120px;
19 | }
20 |
21 | footer {
22 | position: absolute;
23 | bottom: 0;
24 | width: 100%;
25 | background-color: #f5f5f5;
26 | padding: 25px 0;
27 | font-size: 15px;
28 | text-align: center;
29 | text-transform: uppercase;
30 | opacity: 0.6;
31 | transition: opacity .2s ease;
32 | }
33 | footer:hover {
34 | opacity: 1.0;
35 | transition: opacity .2s ease;
36 | }
37 | footer p {
38 | margin: 0;
39 | }
40 |
41 | h3 {
42 | font-size: 23px;
43 | }
44 |
45 | li {
46 | margin-bottom: 3px;
47 | }
48 |
49 | #content img {
50 | max-width: 100%;
51 | padding: 4px;
52 | background-color: #fff;
53 | border: 1px solid #ddd;
54 | border-radius: 4px;
55 | }
56 |
57 | header.navbar {
58 | opacity: 0.9;
59 | }
60 | .navbar .navbar-brand {
61 | font-size: 28px;
62 | height: auto;
63 | line-height: 40px;
64 | margin-left: 20px;
65 | }
66 | .navbar .navbar-brand small {
67 | font-size: 18px;
68 | font-weight: 300;
69 | margin-left: 10px;
70 | }
71 |
72 | @media (min-width: 768px) {
73 | #sidebar {
74 | margin-top: 30px;
75 | }
76 | }
77 | @media (max-width: 960px) {
78 | body {
79 | font-size: 17px;
80 | }
81 | pre {
82 | font-size: 12px;
83 | }
84 | }
85 |
86 | .page-header {
87 | margin-top: 0;
88 | }
89 |
90 | #sidebar .text-muted {
91 | color: #bbbbbb;
92 | }
93 |
94 | pre {
95 | padding: 0;
96 | border-radius: 4px;
97 | margin: 15px;
98 | font-size: 15px;
99 | }
100 | pre code {
101 | border: none;
102 | }
103 |
--------------------------------------------------------------------------------
/docs/development.md:
--------------------------------------------------------------------------------
1 | Development
2 | ===========
3 |
4 | * [Writing system tests](development/writing-system-tests.md)
5 |
6 | --------------------------------------------------------------------------------
7 |
8 | To get ready for contributing to the Ibuildings QA Tools:
9 |
10 | ```sh-session
11 | $ # Check out the repository
12 | $ git clone git@github.com:ibuildingsnl/qa-tools.git
13 | $ # Install the Composer dependencies
14 | $ composer install
15 | $ # Install the Git hooks
16 | $ tools/git/pre-commit-install
17 | $ tools/git/pre-push-install
18 | ```
19 |
20 | ## Building a QA Tools distributable Phar
21 |
22 | The command below will build the QA Tools. For more specifics about building the
23 | Phar, see [Phar](phar.md).
24 |
25 | ```sh-session
26 | $ make build
27 | ```
28 |
29 | ## Making your contribution
30 |
31 | We appreciate you helping out! Please look at the
32 | [Contributing guidelines](../CONTRIBUTING.md) to help get your contribution
33 | accepted.
34 |
35 |
--------------------------------------------------------------------------------
/docs/development/configuration-process.md:
--------------------------------------------------------------------------------
1 | Configuration process
2 | =====================
3 |
4 | The QA Tools configuration process is as follows:
5 |
6 | 0. The developer is "interviewed" the project's name, type, whether the
7 | developer uses Travis, and where all the tools' configuration files ought to be
8 | stored. These answers influence the type of configuration that takes place
9 | directly afterwards.
10 | 0. Based on the project settings (eg. project type), a list of tool
11 | configurators is compiled. Each configurator gets the chance to interview the
12 | developer for more settings pertinent to each configurator's tool. Based on
13 | the developer's answers, the configurator adds tasks to the task directory.
14 | These tasks and how they are executed are defined in the core of QA Tools;
15 | tools cannot create new types of tasks. Examples of tasks are the installation
16 | of a Composer development dependency or the writing of a tool's configuration
17 | file.
18 | 0. In the following execution stage, each task executor is tested for tasks it
19 | supports. Each executor's supported tasks are then passed to each executors
20 | various stages.
21 | 0. The tasks' prerequisites are checked by each executor. An example would
22 | be checking whether the required Composer packages don't conflict with any
23 | installed packages.
24 | 0. The tasks are executed. If a task fails, tasks that have already been
25 | executed are rolled back in reverse order.
26 | 0. Each executor gets the chance to clean up, like discarding any backups of
27 | files it was to write.
28 | 0. The project settings and the answers given to each question are stored in a
29 | configuration file. Based on this configuration file, all question's are
30 | pre-filled on a subsequent run of the QA Tools.
31 |
32 | This process is managed in the [`ConfigurationService`][src-config-service].
33 |
34 | [src-config-service]: ../../src/Core/Service/ConfigurationService.php
35 |
--------------------------------------------------------------------------------
/docs/development/writing-documentation.md:
--------------------------------------------------------------------------------
1 | Writing documentation
2 | =====================
3 |
4 | Documentation is written in Markdown in the `docs/` directories. It is also
5 | compiled to a HTML version by [Couscous][couscous] and deployed
6 | to GitHub Pages when the Travis build against master succeeds. This is
7 | configured in this project's Travis configuration.
8 |
9 | [couscous]: https://couscous.io/
10 |
11 | To preview how the compiled documentation looks, run:
12 |
13 | ```sh-session
14 | $ vendor/bin/couscous preview
15 | ```
16 |
17 | When you add a new Markdown file, and would like it to be included in the
18 | compiled documentation's navigation, add it to this project's Couscous
19 | configuration in `/couscous.yml`. This configuration should speak for itself,
20 | but more information can be found in the
21 | [template's documentation](../couscous/template/README.md) or in
22 | [Couscous' documentation][couscous].
23 |
--------------------------------------------------------------------------------
/docs/phar.md:
--------------------------------------------------------------------------------
1 | Phar
2 | ====
3 |
4 | The QA Tools are distributed as a PHP Archive (Phar) file in order to separate the QA Tools' dependencies from
5 | the host projects' dependencies. The compiled Phar is also able to verify its
6 | own integrity with the provided public key.
7 |
8 | ## Types of builds
9 |
10 | There are two types of build: a test build, and a release build. The test build is used
11 | for system testing and is signed using an insecure, ephemeral private key. The
12 | release build is for release to the public, and is signed using a secure private
13 | key managed by Ibuildings.
14 |
15 | This serves the following purposes:
16 |
17 | 0. The test process can be completely automated on the contributor's machine
18 | and on Travis, the automated build server; the private key used for signing
19 | the test build requires no passphrase.
20 | 0. There is no confusion as to with which private key the build is signed. This
21 | prevents a release of a Phar signed with the test key.
22 |
23 | ## Building the Phar
24 |
25 | [Box][^box] is used for building the QA Tools Phar file, which is configured in
26 | the `box.json` file. It is installed as a Phar file itself to prevent version
27 | conflicts between Box' and QA Tools' dependencies.
28 |
29 | To enable the writing of Phar files, disable the PHP ini setting `phar.readonly`
30 | by setting it to `Off`.
31 |
32 | Run `make build-test` in the project root directory to build the test build.
33 | This creates `./build/test/qa-tools.phar` and `./build/test/qa-tools.phar.pubkey`.
34 |
35 | ## Updating Box
36 | Box is installed during Composer's `post-install-cmd` phase.
37 | To update Box, manually update the source and sha-sum inside `composer.json` under the `extra` parameters.
38 |
39 | [^box]: https://box-project.github.io/box2/
40 | [^secure-phar]: https://mwop.net/blog/2015-12-14-secure-phar-automation.html
41 |
--------------------------------------------------------------------------------
/docs/release-process.md:
--------------------------------------------------------------------------------
1 | Release process
2 | ===============
3 |
4 | The QA Tools' release process is largely automated by [RMT][github-rmt]. The
5 | configured release process, in this order:
6 |
7 | 0. verifies that the working copy is clean;
8 | 0. verifies that the software is in working order by running all tests;
9 | 0. keeps a change log;
10 | 0. creates a new tag according to [semver][semver] rules;
11 | 0. and published the tag to the Git tracked repository `origin`.
12 |
13 | If any of the verification steps fail, the release process is aborted. These
14 | verification steps are there for a very good reason and *may never* be skipped.
15 |
16 | The release build is signed using a separate private key and is managed by
17 | Ibuildings. This key can be found in Ibuildings' LastPass and is named "QA Tools
18 | private key for releases". Place this key in `./signing-key-release.pem`.
19 |
20 | Then, to run the release process, execute the following in a terminal:
21 |
22 | ```sh-session
23 | $ make release
24 | ```
25 |
26 | ## Distributing the release build
27 |
28 | After the new tag has been published, the [Phar](phar.md) built during the
29 | publishing process must be uploaded to the [Releases][github-qa-releases] page
30 | on GitHub.
31 |
32 | 0. Click *Draft a new release*.
33 | 0. Select the tag you just published.
34 | 0. Use the tag as release title.
35 | 0. If it's an unstable version, indicated by a stability label like `#.#.#-beta`, tick the pre-release checkbox. Ticking this checkbox does not have any functional consequences for the self-updating process, but functions primarily as documentation.
36 | 0. Copy this release's documented changes (see the change log) into the
37 | description field.
38 | 0. Attach the Phar and its public key to the release. You find these in the `./build/release/` directory.
39 | 0. Publish the release.
40 |
41 | [github-rmt]: https://github.com/liip/RMT
42 | [semver]: http://semver.org/
43 | [path]: https://en.wikipedia.org/wiki/PATH_(variable)
44 | [github-qa-releases]: https://github.com/ibuildingsnl/qa-tools/releases
45 |
--------------------------------------------------------------------------------
/docs/reporting-a-bug.md:
--------------------------------------------------------------------------------
1 | Reporting a bug
2 | ===============
3 |
4 | Whenever you find a bug in the QA Tools, we kindly ask you to report it. It
5 | helps us make it better!
6 |
7 | Before submitting a bug:
8 |
9 | * double-check the official [documentation][qa-tools-docs] to see if you're not
10 | misusing the tools;
11 | * verify someone else hasn't already reported your issue in the
12 | [issue tracker](qa-tools-issues).
13 |
14 | If your problem definitely looks like a bug, report it using the
15 | [issue tracker](qa-tools-issues) and follow some basic rules:
16 |
17 | * use the title field to clearly describe the issue;
18 | * describe the steps needed to reproduce the bug;
19 | * and give as much detail as possible about your environment (OS, PHP version,
20 | enabled extensions, ...).
21 |
22 | [qa-tools-docs]: https://github.com/ibuildingsnl/qa-tools#documentation
23 | [qa-tools-issues]: https://github.com/ibuildingsnl/qa-tools/issues
24 |
--------------------------------------------------------------------------------
/docs/ubiquitous-language.md:
--------------------------------------------------------------------------------
1 | Ubiquitous language
2 | ===================
3 |
4 | | **Term** | **Explanation** |
5 | | -------------:|:--------------- |
6 | | **Configure** | The process where a *Developer* answers questions pertinent to a specific *Tool*. These answers will result in *Tasks*. |
7 | | **Contributor** | A developer that works on the QA Tools application itself by writing source code, documentation, etc. |
8 | | **Developer** | A developer that uses the QA Tools application to configure QA tools for their project. |
9 | | **Target project** | The project the QA Tools application configures tools for. |
10 | | **Task** | Describes a concrete action to be performed on the target project, like installing a set of Composer packages, or writing an Ant build file. |
11 | | **Tool** | A component that configures an actual QA tool, like PHPUnit, by, for example, writing configuration files to disk. |
12 |
--------------------------------------------------------------------------------
/phpmd.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 | Ibuildings QA Tools Default Ruleset for QA Tools
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | tests
16 |
17 |
18 |
19 |
20 |
21 | src
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/qa-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "QA Tools",
3 | "configurationFilesLocation": ".\/",
4 | "projectTypes": [
5 | "php.other"
6 | ],
7 | "travisEnabled": false,
8 | "answers": {
9 | "4c6702ea73cad3d4fbeb1a275b6dbb4a": "QA Tools",
10 | "82191a2f54943a61240ff714d692663d": ".\/",
11 | "64d5c97247c332c17b131abdde8c873a": "Other PHP Project",
12 | "4735c10b621d2c15142ff92e6ec0a9a9": true,
13 | "1f73d735e7d5a37ff6e8a9c30311a00a": true,
14 | "97016cab401f3bbfaf10dfa47ec8cbd8": true,
15 | "80a50eef71a0a84f0779597a5185008e": true,
16 | "743bcf201e8b6c07fbad359c2bdf79ac": "PSR2",
17 | "be2a788ae62f9166970c6de91c828c53": "Warn when \u003E120. Fail when \u003E150",
18 | "6dd3ae893178cd90a45edaaeceab33f5": false,
19 | "809d51753d308ccf218c0217c00c779d": false,
20 | "5c08b9b1487086e2e506013f8e3fc65f": true,
21 | "c8214ea1830f49699c20dc2b42c4c190": false
22 | }
23 | }
--------------------------------------------------------------------------------
/ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Enforce coding standards
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/Core/Application/Basedir.php:
--------------------------------------------------------------------------------
1 | setName('configure')
23 | ->setDescription('Configure the Ibuildings QA Tools')
24 | ->setHelp('Configure the Ibuildings QA Tools');
25 | }
26 |
27 | protected function execute(InputInterface $input, OutputInterface $output)
28 | {
29 | /** @var InterviewerFactory $interviewerFactory */
30 | $interviewerFactory = $this->container->get('qa_tools.io.cli.interviewer_factory');
31 | $interviewer = $interviewerFactory->createWith($input, $output);
32 |
33 | /** @var ConfigurationService $service */
34 | $service = $this->container->get('qa_tools.configuration_service');
35 | if (!$service->configureProject($interviewer, new Directory(getcwd()))) {
36 | return 1;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Core/Application/Command/PreCommitCommand.php:
--------------------------------------------------------------------------------
1 | setName('configure:pre-commit')
21 | ->setDescription('Configure the pre-commit hook for the Ibuildings QA Tools')
22 | ->setHelp('Configure the pre-commit hook for the Ibuildings QA Tools');
23 | }
24 |
25 | protected function execute(InputInterface $input, OutputInterface $output)
26 | {
27 | /** @var InterviewerFactory $interviewerFactory */
28 | $interviewerFactory = $this->container->get('qa_tools.io.cli.interviewer_factory');
29 | $interviewer = $interviewerFactory->createWith($input, $output);
30 |
31 | $installer = $this->container->get('qa_tools.git.hook_installer');
32 | $projectRoot = new Directory(getcwd());
33 |
34 | $installer->installPreCommitHook($interviewer, $projectRoot);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Core/Application/Command/PrePushCommand.php:
--------------------------------------------------------------------------------
1 | setName('configure:pre-push')
21 | ->setDescription('Configure up the pre-push hook for the Ibuildings QA Tools')
22 | ->setHelp('Configure the pre-push hook for the Ibuildings QA Tools');
23 | }
24 |
25 | protected function execute(InputInterface $input, OutputInterface $output)
26 | {
27 | /** @var InterviewerFactory $interviewerFactory */
28 | $interviewerFactory = $this->container->get('qa_tools.io.cli.interviewer_factory');
29 | $interviewer = $interviewerFactory->createWith($input, $output);
30 |
31 | $installer = $this->container->get('qa_tools.git.hook_installer');
32 | $projectRoot = new Directory(getcwd());
33 |
34 | $installer->installPrePushHook($interviewer, $projectRoot);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Core/Application/Compiler/RegisterConfiguratorsCompilerPass.php:
--------------------------------------------------------------------------------
1 | findDefinition('qa_tools.configurator_repository');
17 | $taggedConfigurators = $container->findTaggedServiceIds('qa_tools.tool');
18 |
19 | foreach ($taggedConfigurators as $configurator => $tags) {
20 | foreach ($tags as $tag) {
21 | if (!isset($tag['project_type'])) {
22 | throw new LogicException(sprintf(
23 | 'Cannot register Configurator "%s" for a ProjectType: property "project_type" not found on tag',
24 | $configurator
25 | ));
26 | }
27 |
28 | $projectType = new ProjectType($tag['project_type']);
29 | $projectTypeDefinition = new Definition(ProjectType::class, [$projectType->getProjectType()]);
30 |
31 | $configuratorRepositoryDefinition->addMethodCall(
32 | 'add',
33 | [
34 | new Reference($configurator),
35 | $projectTypeDefinition,
36 | ]
37 | );
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Core/Assert/Assertion.php:
--------------------------------------------------------------------------------
1 | buildIdentifier = $targetIdentifier;
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function getBuildIdentifier()
45 | {
46 | return $this->buildIdentifier;
47 | }
48 |
49 | /**
50 | * @param Build $other
51 | * @return bool
52 | */
53 | public function equals(Build $other)
54 | {
55 | return $this->buildIdentifier === $other->buildIdentifier;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Core/Build/Snippet.php:
--------------------------------------------------------------------------------
1 | contents = $contents;
44 | $this->target = $target;
45 | }
46 |
47 | /**
48 | * @return string
49 | */
50 | public function getContents()
51 | {
52 | return $this->contents;
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getTarget()
59 | {
60 | return $this->target;
61 | }
62 |
63 | /**
64 | * @param Snippet $other
65 | * @return bool
66 | */
67 | public function equals(Snippet $other)
68 | {
69 | return $this->target === $other->target
70 | && $this->contents === $other->contents;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Core/Build/Tool.php:
--------------------------------------------------------------------------------
1 | toolIdentifier = $toolIdentifier;
32 | }
33 |
34 | /**
35 | * @param Tool $other
36 | * @param string[] $toolOrder
37 | * @return int
38 | */
39 | public function compare(Tool $other, array $toolOrder)
40 | {
41 | $otherIndex = array_search($other->toolIdentifier, $toolOrder);
42 | $thisIndex = array_search($this->toolIdentifier, $toolOrder);
43 |
44 | if ($otherIndex === $thisIndex) {
45 | return 0;
46 | }
47 |
48 | if ($otherIndex > $thisIndex) {
49 | return -1;
50 | }
51 |
52 | return 1;
53 | }
54 |
55 | /**
56 | * @param Tool $other
57 | * @return bool
58 | */
59 | public function equals(Tool $other)
60 | {
61 | return $this->toolIdentifier == $other->toolIdentifier;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Core/Composer/CliComposerProjectFactory.php:
--------------------------------------------------------------------------------
1 | logger = $logger;
18 | }
19 |
20 | public function forDirectory($directory)
21 | {
22 | Assertion::string($directory, 'Composer project directory ought to be a string, got "%s" of type "%s"');
23 |
24 | $envComposerPath = getenv('COMPOSER_BIN');
25 | $pharPath = $directory . '/composer.phar';
26 |
27 | if ($envComposerPath) {
28 | $composerBinary = $envComposerPath;
29 | } elseif (file_exists($pharPath)) {
30 | $composerBinary = $pharPath;
31 | } else {
32 | $composerBinary = 'composer';
33 | }
34 |
35 | return new CliComposerProject($directory, $composerBinary, $this->logger);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Core/Composer/Configuration.php:
--------------------------------------------------------------------------------
1 | composerJson = $composerJson;
50 | $this->composerLockJson = $composerLockJson;
51 | }
52 |
53 | /**
54 | * @return bool
55 | */
56 | public function hasLockedDependencies()
57 | {
58 | return $this->composerLockJson !== null;
59 | }
60 |
61 | /**
62 | * @return string
63 | */
64 | public function getComposerJson()
65 | {
66 | return $this->composerJson;
67 | }
68 |
69 | /**
70 | * @return string|null
71 | */
72 | public function getComposerLockJson()
73 | {
74 | return $this->composerLockJson;
75 | }
76 |
77 | /**
78 | * @param Configuration $configuration
79 | * @return boolean
80 | */
81 | public function equals(Configuration $configuration)
82 | {
83 | return $this->composerJson === $configuration->composerJson
84 | && $this->composerLockJson === $configuration->composerLockJson;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Core/Composer/Package.php:
--------------------------------------------------------------------------------
1 | name = $name;
34 | $this->versionConstraint = $versionConstraint;
35 | }
36 |
37 | /**
38 | * @param PackageVersionConstraint $versionConstraint
39 | * @return bool
40 | */
41 | public function versionConstraintEquals(PackageVersionConstraint $versionConstraint)
42 | {
43 | return $this->versionConstraint->equals($versionConstraint);
44 | }
45 |
46 | /**
47 | * @param Package $other
48 | * @return bool
49 | */
50 | public function equals(Package $other)
51 | {
52 | return $this->name->equals($other->name)
53 | && $this->versionConstraint->equals($other->versionConstraint);
54 | }
55 |
56 | /**
57 | * Returns this package's descriptor, eg. "phpmd/phpmd:^2.0".
58 | *
59 | * @return string
60 | */
61 | public function getDescriptor()
62 | {
63 | return sprintf(
64 | '%s:%s',
65 | $this->getName()->getName(),
66 | $this->getVersionConstraint()->getConstraint()
67 | );
68 | }
69 |
70 | /**
71 | * @return PackageName
72 | */
73 | public function getName()
74 | {
75 | return $this->name;
76 | }
77 |
78 | /**
79 | * @return PackageVersionConstraint
80 | */
81 | public function getVersionConstraint()
82 | {
83 | return $this->versionConstraint;
84 | }
85 |
86 | public function __toString()
87 | {
88 | return sprintf('Package("%s:%s")', $this->name->getName(), $this->versionConstraint->getConstraint());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Core/Composer/PackageName.php:
--------------------------------------------------------------------------------
1 | name = $name;
27 | }
28 |
29 | /**
30 | * @param PackageName $other
31 | * @return bool
32 | */
33 | public function equals(PackageName $other)
34 | {
35 | return $this->name === $other->name;
36 | }
37 |
38 | /**
39 | * @return string
40 | */
41 | public function getName()
42 | {
43 | return $this->name;
44 | }
45 |
46 | public function __toString()
47 | {
48 | return sprintf('PackageName("%s")', $this->name);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Core/Composer/PackageVersionConstraint.php:
--------------------------------------------------------------------------------
1 | parseConstraints($constraint);
32 | } catch (UnexpectedValueException $e) {
33 | throw new InvalidArgumentException(
34 | sprintf('Package version constraint "%s" is invalid', $constraint)
35 | );
36 | }
37 |
38 | return new PackageVersionConstraint($constraint, $parsedConstraint);
39 | }
40 |
41 | /**
42 | * @param string $constraint
43 | * @param string $parsedConstraint
44 | */
45 | private function __construct($constraint, $parsedConstraint)
46 | {
47 | $this->constraint = $constraint;
48 | $this->parsedConstraint = $parsedConstraint;
49 | }
50 |
51 | /**
52 | * @param PackageVersionConstraint $other
53 | * @return bool
54 | */
55 | public function equals(PackageVersionConstraint $other)
56 | {
57 | return $this->parsedConstraint === $other->parsedConstraint;
58 | }
59 |
60 | /**
61 | * @return string
62 | */
63 | public function getConstraint()
64 | {
65 | return $this->constraint;
66 | }
67 |
68 | public function __toString()
69 | {
70 | return sprintf('PackageVersionConstraint("%s", parsed="%s")', $this->constraint, $this->parsedConstraint);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Core/Composer/Project.php:
--------------------------------------------------------------------------------
1 | cause = $cause;
24 | }
25 |
26 | /**
27 | * Returns a detailed, ideally human-readable, explanation of the cause of this exception.
28 | *
29 | * @return string
30 | */
31 | public function getCause()
32 | {
33 | return $this->cause;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Core/Configuration/Configuration.php:
--------------------------------------------------------------------------------
1 | project = $project;
41 | $this->answers = $answers;
42 | }
43 |
44 | public function reconfigureProject(Project $project)
45 | {
46 | $this->project = $project;
47 | }
48 |
49 | /**
50 | * @param QuestionId $questionId
51 | * @param Answer $answer
52 | */
53 | public function answer(QuestionId $questionId, Answer $answer)
54 | {
55 | $this->answers[$questionId->getQuestionId()] = $answer;
56 | }
57 |
58 | /**
59 | * @return Project|null
60 | */
61 | public function getProject()
62 | {
63 | return $this->project;
64 | }
65 |
66 | /**
67 | * @param QuestionId $questionId
68 | * @return bool
69 | */
70 | public function hasAnswer(QuestionId $questionId)
71 | {
72 | return isset($this->answers[$questionId->getQuestionId()]);
73 | }
74 |
75 | /**
76 | * @param QuestionId $questionId
77 | * @return Answer
78 | */
79 | public function getAnswer(QuestionId $questionId)
80 | {
81 | if (!$this->hasAnswer($questionId)) {
82 | throw new RuntimeException(sprintf('No answer with id "%s" stored in configuration', $questionId));
83 | }
84 |
85 | return $this->answers[$questionId->getQuestionId()];
86 | }
87 |
88 | /**
89 | * @return Answer[]
90 | */
91 | public function getAnswers()
92 | {
93 | return $this->answers;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Core/Configuration/ConfigurationRepository.php:
--------------------------------------------------------------------------------
1 | storedConfiguration !== null;
17 | }
18 |
19 | public function load()
20 | {
21 | if (!$this->configurationExists()) {
22 | throw new RuntimeException('No configuration stored in memory');
23 | }
24 |
25 | return $this->storedConfiguration;
26 | }
27 |
28 | public function save(Configuration $configuration)
29 | {
30 | $this->storedConfiguration = $configuration;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Core/Configuration/InMemoryTaskDirectory.php:
--------------------------------------------------------------------------------
1 | project = $project;
24 | $this->tasks = new TaskList();
25 | }
26 |
27 | public function registerTask(Task $task)
28 | {
29 | $this->tasks = $this->tasks->add($task);
30 | }
31 |
32 | /**
33 | * @param callable $predicate
34 | * @return TaskList
35 | */
36 | public function filterTasks(callable $predicate)
37 | {
38 | return $this->tasks->filter($predicate);
39 | }
40 |
41 | /**
42 | * @return TaskList
43 | */
44 | public function getTasks()
45 | {
46 | return $this->tasks;
47 | }
48 |
49 | public function getProject()
50 | {
51 | return $this->project;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Core/Configuration/InMemoryTaskDirectoryFactory.php:
--------------------------------------------------------------------------------
1 | interviewer = $interviewer;
34 | $this->configuration = $configuration;
35 | }
36 |
37 | public function setScope($scope)
38 | {
39 | Assertion::string($scope);
40 |
41 | $this->scope = $scope;
42 | }
43 |
44 | public function ask(QuestionInterface $question)
45 | {
46 | $questionIdentifier = QuestionId::fromScopeAndQuestion($this->scope, $question);
47 |
48 | if ($this->configuration->hasAnswer($questionIdentifier)) {
49 | $previousAnswer = $this->configuration->getAnswer($questionIdentifier);
50 | $question = $question->withDefaultAnswer($previousAnswer);
51 | }
52 |
53 | $givenAnswer = $this->interviewer->ask($question);
54 | $this->configuration->answer($questionIdentifier, $givenAnswer);
55 |
56 | return $givenAnswer;
57 | }
58 |
59 | public function notice($sentence)
60 | {
61 | $this->interviewer->notice($sentence);
62 | }
63 |
64 | public function giveDetails($sentence)
65 | {
66 | $this->interviewer->giveDetails($sentence);
67 | }
68 |
69 | public function success($sentence)
70 | {
71 | $this->interviewer->success($sentence);
72 | }
73 |
74 | public function warn($sentence)
75 | {
76 | $this->interviewer->warn($sentence);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Core/Configuration/QuestionId.php:
--------------------------------------------------------------------------------
1 | getQuestion()));
29 | }
30 |
31 | /**
32 | * @param string $questionId
33 | */
34 | public function __construct($questionId)
35 | {
36 | Assertion::nonEmptyString(
37 | $questionId,
38 | 'Expected non-empty string for "%3$s", got "%s" of type "%s"',
39 | 'Question ID ought to be a non-empty string, got "%s" of type "%s"'
40 | );
41 |
42 | $this->questionId = $questionId;
43 | }
44 |
45 | /**
46 | * @param QuestionId $other
47 | * @return bool
48 | */
49 | public function equals(QuestionId $other)
50 | {
51 | return $this->questionId === $other->questionId;
52 | }
53 |
54 | /**
55 | * @return string
56 | */
57 | public function getQuestionId()
58 | {
59 | return $this->questionId;
60 | }
61 |
62 | public function __toString()
63 | {
64 | return sprintf('%s("%s")', self::class, $this->questionId);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Core/Configuration/TaskDirectory.php:
--------------------------------------------------------------------------------
1 | templateEngine = $templateEngine;
18 | }
19 |
20 | /**
21 | * @param string $template
22 | * @param array $params
23 | * @return string
24 | */
25 | public function renderTemplate($template, array $params = [])
26 | {
27 | Assertion::nonEmptyString($template, 'Expected non-empty string for "%3$s", got "%s" of type "%s"', 'template');
28 |
29 | return $this->templateEngine->render($template, $params);
30 | }
31 |
32 | /**
33 | * @param string $path
34 | */
35 | public function setTemplatePath($path)
36 | {
37 | Assertion::nonEmptyString($path, 'Expected non-empty string for "%3$s", got "%s" of type "%s"', 'path');
38 |
39 | $this->templateEngine->setPath($path);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Core/Configuration/ToolConfigurator.php:
--------------------------------------------------------------------------------
1 | taskHelperSet = $taskHelperSet;
25 | $this->container = $container;
26 | }
27 |
28 | public function configure(
29 | ConfiguratorList $configurators,
30 | ScopedInterviewer $interviewer,
31 | TaskDirectory $taskDirectory
32 | ) {
33 | foreach ($configurators as $configurator) {
34 | /** @var Configurator $configurator */
35 | $interviewer->setScope($configurator->getToolClassName());
36 |
37 | $resourcePath = $this->container->getParameter(
38 | sprintf('tool.%s.resource_path', $configurator->getToolClassName())
39 | );
40 | $templatePath = $resourcePath . '/templates';
41 | $this->taskHelperSet->setTemplatePath($templatePath);
42 |
43 | $configurator->configure($interviewer, $taskDirectory, $this->taskHelperSet);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Core/Configurator/Configurator.php:
--------------------------------------------------------------------------------
1 | configurators = $configurators;
21 | }
22 |
23 | /**
24 | * @param Configurator $configurator
25 | * @return bool
26 | */
27 | public function contains(Configurator $configurator)
28 | {
29 | return in_array($configurator, $this->configurators);
30 | }
31 |
32 | /**
33 | * @param Configurator $configurator
34 | * @return ConfiguratorList
35 | */
36 | public function append(Configurator $configurator)
37 | {
38 | return new self(array_merge($this->configurators, $configurator));
39 | }
40 |
41 | public function appendList(ConfiguratorList $other)
42 | {
43 | return new self(array_merge($this->configurators, $other->configurators));
44 | }
45 |
46 | public function getIterator()
47 | {
48 | return new ArrayIterator($this->configurators);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Core/Configurator/ConfiguratorRepository.php:
--------------------------------------------------------------------------------
1 | getProjectType();
26 |
27 | if (!key_exists($projectTypeKey, $this->registeredConfigurators)) {
28 | $this->registeredConfigurators[$projectTypeKey] = [];
29 | }
30 |
31 | $toolClassName = $configurator->getToolClassName();
32 | if (array_key_exists($toolClassName, $this->registeredConfigurators[$projectTypeKey])) {
33 | throw new LogicException(
34 | sprintf(
35 | 'Cannot register Configurator "%s" under ProjectType "%s"; ' .
36 | 'Configurator "%s" has already been registered for the same tool ("%s")',
37 | get_class($configurator),
38 | $projectType->getProjectType(),
39 | get_class($this->registeredConfigurators[$projectTypeKey][$toolClassName]),
40 | $toolClassName
41 | )
42 | );
43 | }
44 |
45 | $this->registeredConfigurators[$projectTypeKey][$toolClassName] = $configurator;
46 | }
47 |
48 | /**
49 | * @param Project $project
50 | * @return ConfiguratorList
51 | */
52 | public function getConfiguratorsForProject(Project $project)
53 | {
54 | $configurators = new ConfiguratorList([]);
55 |
56 | foreach ($project->getProjectTypes() as $projectType) {
57 | if (isset($this->registeredConfigurators[$projectType->getProjectType()])) {
58 | $configurators = $configurators->appendList(
59 | new ConfiguratorList($this->registeredConfigurators[$projectType->getProjectType()])
60 | );
61 | }
62 | }
63 |
64 | return $configurators;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Core/Exception/InvalidAnswerGivenException.php:
--------------------------------------------------------------------------------
1 | fileHandler = $fileHandler;
33 | $this->questionHelper = $questionHelper;
34 | $this->consoleQuestionFactory = $consoleQuestionFactory;
35 | }
36 |
37 | /**
38 | * @param InputInterface $input
39 | * @param OutputInterface $output
40 | * @return Interviewer
41 | */
42 | public function createWith(InputInterface $input, OutputInterface $output)
43 | {
44 | return new Interviewer($input, $output, $this->questionHelper, $this->consoleQuestionFactory);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Core/IO/Cli/Validator/TextualAnswerValidator.php:
--------------------------------------------------------------------------------
1 | answers = $answers;
24 | }
25 |
26 | /**
27 | * @param TextualAnswer $other
28 | * @return bool
29 | */
30 | public function contain(TextualAnswer $other)
31 | {
32 | /** @var TextualAnswer $answer */
33 | foreach ($this->answers as $answer) {
34 | if ($answer->equals($other)) {
35 | return true;
36 | }
37 | }
38 |
39 | return false;
40 | }
41 |
42 | /**
43 | * @param Answer $other
44 | * @return bool
45 | */
46 | public function equals(Answer $other)
47 | {
48 | if (!$this instanceof self || count($other) !== count($this)) {
49 | return false;
50 | }
51 |
52 | foreach ($other as $otherAnswer) {
53 | if (!$this->contain($otherAnswer)) {
54 | return false;
55 | }
56 | }
57 |
58 | return true;
59 | }
60 |
61 | public function getRaw()
62 | {
63 | return array_map(
64 | function (TextualAnswer $answer) {
65 | return $answer->getRaw();
66 | },
67 | $this->answers
68 | );
69 | }
70 |
71 | public function getIterator()
72 | {
73 | return new ArrayIterator($this->answers);
74 | }
75 |
76 | public function count()
77 | {
78 | return count($this->answers);
79 | }
80 |
81 | public function convertToString()
82 | {
83 | return implode(', ', $this->convertToArrayOfStrings());
84 | }
85 |
86 | /**
87 | * @return string[]
88 | */
89 | public function convertToArrayOfStrings()
90 | {
91 | return array_map(function (TextualAnswer $answer) {
92 | return $answer->getAnswer();
93 | }, $this->answers);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Core/Interviewer/Answer/NoDefaultAnswer.php:
--------------------------------------------------------------------------------
1 | answer = $answer;
18 | }
19 |
20 | /**
21 | * @param Answer $other
22 | * @return bool
23 | */
24 | public function equals(Answer $other)
25 | {
26 | return $other instanceof self && $this->answer === $other->answer;
27 | }
28 |
29 | /**
30 | * @return string
31 | */
32 | public function getAnswer()
33 | {
34 | return $this->answer;
35 | }
36 |
37 | public function getRaw()
38 | {
39 | return $this->answer;
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function convertToString()
46 | {
47 | return $this->answer;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Core/Interviewer/Answer/YesOrNoAnswer.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | public static function yes()
21 | {
22 | return new self(self::YES);
23 | }
24 |
25 | /**
26 | * @return YesOrNoAnswer
27 | */
28 | public static function no()
29 | {
30 | return new self(self::NO);
31 | }
32 |
33 | private function __construct($answer)
34 | {
35 | Assertion::boolean($answer);
36 |
37 | $this->answer = $answer;
38 | }
39 |
40 | /**
41 | * @param Answer $other
42 | * @return bool
43 | */
44 | public function equals(Answer $other)
45 | {
46 | return $other instanceof self && $this->answer === $other->answer;
47 | }
48 |
49 | /**
50 | * @return string
51 | */
52 | public function getRaw()
53 | {
54 | return $this->answer;
55 | }
56 |
57 | /**
58 | * @param $yesOrNo
59 | * @return boolean
60 | */
61 | public function is($yesOrNo)
62 | {
63 | Assertion::boolean($yesOrNo);
64 |
65 | return $this->answer === $yesOrNo;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Core/Interviewer/AutomatedResponseInterviewer.php:
--------------------------------------------------------------------------------
1 | recordedAnswers, [$partialQuestionText, $answer]);
27 | }
28 |
29 | /**
30 | * Records that the question's default answer ought to be given when a
31 | * question's text matches the partial question text.
32 | *
33 | * @param string $partialQuestionText
34 | * @return void
35 | */
36 | public function respondWithDefaultAnswerTo($partialQuestionText)
37 | {
38 | $this->questionsToAnswerToWithDefault[] = $partialQuestionText;
39 | }
40 |
41 | public function ask(Question $question)
42 | {
43 | foreach ($this->recordedAnswers as list($partialQuestionText, $answer)) {
44 | if (strpos($question, $partialQuestionText) !== false) {
45 | return $answer;
46 | }
47 | }
48 | foreach ($this->questionsToAnswerToWithDefault as $partialQuestionText) {
49 | if (strpos($question, $partialQuestionText) !== false) {
50 | if (!$question->hasDefaultAnswer()) {
51 | throw new RuntimeException(sprintf('No default answer available for question "%s"', $question));
52 | }
53 | return $question->getDefaultAnswer();
54 | }
55 | }
56 |
57 | throw new RuntimeException(sprintf('No answer recorded for question "%s"', $question));
58 | }
59 |
60 | public function notice($sentence)
61 | {
62 | }
63 |
64 | public function giveDetails($sentence)
65 | {
66 | }
67 |
68 | public function success($sentence)
69 | {
70 | }
71 |
72 | public function warn($sentence)
73 | {
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Core/Interviewer/Interviewer.php:
--------------------------------------------------------------------------------
1 | question = $question;
32 | $this->defaultAnswer = $defaultAnswer;
33 | }
34 |
35 | /**
36 | * @param TextualQuestion $other
37 | * @return bool
38 | */
39 | public function equals(TextualQuestion $other)
40 | {
41 | return $this->question === $other->question && $this->defaultAnswer->equals($other->defaultAnswer);
42 | }
43 |
44 | public function hasDefaultAnswer()
45 | {
46 | return !$this->defaultAnswer instanceof NoDefaultAnswer;
47 | }
48 |
49 | public function getQuestion()
50 | {
51 | return $this->question;
52 | }
53 |
54 | public function getDefaultAnswer()
55 | {
56 | return $this->defaultAnswer;
57 | }
58 |
59 | public function withDefaultAnswer(Answer $answer)
60 | {
61 | return new TextualQuestion($this->question, $answer);
62 | }
63 |
64 | /**
65 | * @return string
66 | */
67 | public function __toString()
68 | {
69 | return sprintf('%s(question="%s")', self::class, $this->question);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Core/Interviewer/Question/YesOrNoQuestion.php:
--------------------------------------------------------------------------------
1 | question = $question;
31 | $this->defaultAnswer = $defaultAnswer;
32 | }
33 |
34 | /**
35 | * @param YesOrNoQuestion $other
36 | * @return bool
37 | */
38 | public function equals(YesOrNoQuestion $other)
39 | {
40 | return $this->question === $other->question && $this->defaultAnswer->equals($other->defaultAnswer);
41 | }
42 |
43 | public function hasDefaultAnswer()
44 | {
45 | return !$this->defaultAnswer instanceof NoDefaultAnswer;
46 | }
47 |
48 | public function withDefaultAnswer(Answer $answer)
49 | {
50 | return new YesOrNoQuestion($this->question, $answer);
51 | }
52 |
53 | public function getQuestion()
54 | {
55 | return $this->question;
56 | }
57 |
58 | public function getDefaultAnswer()
59 | {
60 | return $this->defaultAnswer;
61 | }
62 |
63 | /**
64 | * @return string
65 | */
66 | public function __toString()
67 | {
68 | return sprintf('%s(question="%s")', self::class, $this->question);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Core/Interviewer/ScopedInterviewer.php:
--------------------------------------------------------------------------------
1 | directory = $directory;
31 | }
32 |
33 | /**
34 | * @param Directory $directory
35 | * @return bool
36 | */
37 | public function equals(Directory $directory)
38 | {
39 | return $this->directory === $directory->directory;
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function getDirectory()
46 | {
47 | return str_replace('/', DIRECTORY_SEPARATOR, $this->directory);
48 | }
49 |
50 | public function __toString()
51 | {
52 | return sprintf('Directory("%s")', $this->directory);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Core/Project/ProjectTypeSet.php:
--------------------------------------------------------------------------------
1 | initializeWith($projectType);
23 | }
24 | }
25 |
26 | /**
27 | * @param ProjectType $projectType The project type to search for.
28 | * @return boolean TRUE if the collection contains the element, FALSE otherwise.
29 | */
30 | public function contains(ProjectType $projectType)
31 | {
32 | foreach ($this->projectTypes as $existingProjectType) {
33 | if ($projectType->equals($existingProjectType)) {
34 | return true;
35 | }
36 | }
37 |
38 | return false;
39 | }
40 |
41 | /**
42 | * @param ProjectTypeSet $other
43 | * @return bool
44 | */
45 | public function equals(ProjectTypeSet $other)
46 | {
47 | if (count($this->projectTypes) !== count($other->projectTypes)) {
48 | return false;
49 | }
50 |
51 | foreach ($this->projectTypes as $projectType) {
52 | if (!$other->contains($projectType)) {
53 | return false;
54 | }
55 | }
56 |
57 | return true;
58 | }
59 |
60 | /**
61 | * @return ProjectType[]
62 | */
63 | public function asArray()
64 | {
65 | return $this->projectTypes;
66 | }
67 |
68 | public function getIterator()
69 | {
70 | return new ArrayIterator($this->projectTypes);
71 | }
72 |
73 | public function count()
74 | {
75 | return count($this->projectTypes);
76 | }
77 |
78 | /**
79 | * @param ProjectType $projectType
80 | */
81 | private function initializeWith(ProjectType $projectType)
82 | {
83 | if ($this->contains($projectType)) {
84 | return;
85 | }
86 |
87 | $this->projectTypes[] = $projectType;
88 | }
89 |
90 | public function __toString()
91 | {
92 | return sprintf(
93 | 'ProjectTypeSet[%d](%s)',
94 | count($this->projectTypes),
95 | join(', ', array_map('strval', $this->projectTypes))
96 | );
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Core/Resources/config/config.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | qa_tools.configuration_location: "./qa-tools.json"
3 |
4 | # Path relative to the application entrypoint (./bin/qa-tools)
5 | qa_tools.ant_template_location: "../src/Core/Resources/templates"
6 |
7 | qa_tools.ant.tool_priorities: ["phplint", "phpcs", "phpmd"]
8 |
--------------------------------------------------------------------------------
/src/Core/Resources/config/task_executors.yml:
--------------------------------------------------------------------------------
1 | services:
2 | qa_tools.task.install_composer_dev_dependency_task_executor:
3 | class: Ibuildings\QaTools\Core\Task\Executor\InstallComposerDevDependencyTaskExecutor
4 | arguments:
5 | - "@qa_tools.composer.project_factory"
6 | tags: [{ name: qa_tools.task_executor, priority: 10 }]
7 |
8 | qa_tools.task.write_file_task_executor:
9 | class: Ibuildings\QaTools\Core\Task\Executor\WriteFileTaskExecutor
10 | arguments:
11 | - "@qa_tools.file_handler"
12 | tags: [{ name: qa_tools.task_executor, priority: 0 }]
13 |
14 | qa_tools.task.add_build_task_executor:
15 | class: Ibuildings\QaTools\Core\Task\Executor\AddBuildTaskExecutor
16 | arguments:
17 | - "@qa_tools.file_handler"
18 | - "@qa_tools.template_engine"
19 | - "%qa_tools.ant_template_location%"
20 | - "%qa_tools.ant.tool_priorities%"
21 | tags: [{ name: qa_tools.task_executor, priority: 5 }]
22 |
--------------------------------------------------------------------------------
/src/Core/Resources/templates/build.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {% if precommit_snippets | length > 0 %}
9 |
10 |
11 | {{ precommit_snippets | join('\n') | raw }}
12 | {% endif %}
13 |
14 | {% if main_snippets | length > 0 %}
15 |
16 |
17 | {{ main_snippets | join('\n')| raw }}
18 | {% endif %}
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Core/Task/AddAntBuildTask.php:
--------------------------------------------------------------------------------
1 | tool = $tool;
33 | $this->snippet = $snippet;
34 | $this->build = $build;
35 | }
36 |
37 | /**
38 | * @param AddAntBuildTask $other
39 | * @param string[] $toolOrder
40 | * @return int
41 | */
42 | public function compare(AddAntBuildTask $other, array $toolOrder)
43 | {
44 | return $this->tool->compare($other->tool, $toolOrder);
45 | }
46 |
47 | /**
48 | * @return string
49 | */
50 | public function getSnippetContents()
51 | {
52 | return $this->snippet->getContents();
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getSnippetTargetIdentifier()
59 | {
60 | return $this->snippet->getTarget();
61 | }
62 |
63 | /**
64 | * @param Build $build
65 | * @return bool
66 | */
67 | public function hasTarget(Build $build)
68 | {
69 | return $this->build->equals($build);
70 | }
71 |
72 | /**
73 | * @param AddAntBuildTask $other
74 | * @return bool
75 | */
76 | public function equals(AddAntBuildTask $other)
77 | {
78 | return $this->build->equals($other->build)
79 | && $this->tool->equals($other->tool)
80 | && $this->snippet->equals($other->snippet);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Core/Task/Executor/ArrayExecutorCollection.php:
--------------------------------------------------------------------------------
1 | executors = $executors;
26 | }
27 |
28 | public function findExecutorsWithAtLeastOneTaskToExecute(TaskDirectory $taskDirectory)
29 | {
30 | return new ArrayExecutorCollection(
31 | array_filter(
32 | $this->executors,
33 | function (Executor $executor) use ($taskDirectory) {
34 | return count($taskDirectory->filterTasks([$executor, 'supports'])) > 0;
35 | }
36 | )
37 | );
38 | }
39 |
40 | public function count()
41 | {
42 | return count($this->executors);
43 | }
44 |
45 | public function getIterator()
46 | {
47 | return new ArrayIterator($this->executors);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Core/Task/Executor/Executor.php:
--------------------------------------------------------------------------------
1 | packageName = $packageName;
27 | $this->packageVersionConstraint = $packageVersionConstraint;
28 | }
29 |
30 | /**
31 | * @return string
32 | */
33 | public function getPackageName()
34 | {
35 | return $this->packageName;
36 | }
37 |
38 | /**
39 | * @return string
40 | */
41 | public function getPackageVersionConstraint()
42 | {
43 | return $this->packageVersionConstraint;
44 | }
45 |
46 | public function __toString()
47 | {
48 | return sprintf(
49 | 'InstallComposerDevDependencyTask("%s:%s")',
50 | $this->packageName,
51 | $this->packageVersionConstraint
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Core/Task/Task.php:
--------------------------------------------------------------------------------
1 | filePath = $filePath;
37 | $this->fileContents = $fileContents;
38 | $this->mode = $mode;
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function getFilePath()
45 | {
46 | return $this->filePath;
47 | }
48 |
49 | /**
50 | * @return string
51 | */
52 | public function getFileContents()
53 | {
54 | return $this->fileContents;
55 | }
56 |
57 | /**
58 | * @return int
59 | */
60 | public function getMode()
61 | {
62 | return $this->mode;
63 | }
64 |
65 | public function __toString()
66 | {
67 | return sprintf(
68 | 'WriteFileTask(filePath="%s", fileContents="%s, mode="%o")',
69 | $this->filePath,
70 | substr($this->fileContents, 0, 20),
71 | $this->mode
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Core/Templating/Escape.php:
--------------------------------------------------------------------------------
1 | '"',
21 | "'" => ''',
22 | '<' => '<',
23 | '>' => '>',
24 | '&' => '&',
25 | ]
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Core/Templating/TemplateEngine.php:
--------------------------------------------------------------------------------
1 | twig = $twig;
20 | }
21 |
22 | /**
23 | * @param string $path A path relative to the application entrypoint `./bin/qa-tools`.
24 | */
25 | public function setPath($path)
26 | {
27 | Assertion::string($path);
28 |
29 | $this->twig->setLoader(new Twig_Loader_Filesystem(Basedir::get() . '/'. $path));
30 | }
31 |
32 | /**
33 | * @param string $template
34 | * @param array $params
35 | * @return string
36 | */
37 | public function render($template, array $params)
38 | {
39 | Assertion::string($template);
40 |
41 | return $this->twig->render($template, $params);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Core/Templating/TwigFactory.php:
--------------------------------------------------------------------------------
1 | true,
17 | ]);
18 |
19 | /** @var CoreExtension $coreExtension */
20 | $coreExtension = $twig->getExtension('core');
21 | $coreExtension->setEscaper('xml', [Escape::class, 'xml']);
22 |
23 | return $twig;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Core/Tool/AbstractTool.php:
--------------------------------------------------------------------------------
1 | determineResourcePath();
17 |
18 | $containerBuilder->setParameter('tool.' . static::class . '.resource_path', $resourcePath);
19 | $configurationFileLoader = new YamlFileLoader(
20 | $containerBuilder,
21 | new FileLocator(Basedir::get() . '/' . $resourcePath . '/config')
22 | );
23 |
24 | foreach ($this->getConfigurationFiles() as $configurationFile) {
25 | $configurationFileLoader->load($configurationFile);
26 | }
27 | }
28 |
29 | /**
30 | * Returns the path to this tool's resources relative to the application
31 | * entrypoint `./bin/qa-tools`.
32 | *
33 | * @return string
34 | */
35 | protected function determineResourcePath()
36 | {
37 | $toolReflection = new ReflectionClass($this);
38 | $toolFilePath = $toolReflection->getFileName();
39 | $absoluteResourcesPath = dirname($toolFilePath) . '/Resources';
40 |
41 | // dirname() is used to traverse up several directories. `../` directories
42 | // are not supported by Filesystem::makePathRelative().
43 | $projectDirectory = dirname(dirname(dirname(__DIR__)));
44 |
45 | $fs = new Filesystem();
46 | $relativeResourcesPath = $fs->makePathRelative(
47 | $absoluteResourcesPath,
48 | $projectDirectory . '/bin'
49 | );
50 |
51 | return $relativeResourcesPath;
52 | }
53 |
54 | /**
55 | * @return string[]
56 | */
57 | protected function getConfigurationFiles()
58 | {
59 | return [
60 | 'configurators.yml'
61 | ];
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Core/Tool/Tool.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Tool/Behat/Resources/templates/behat.yml:
--------------------------------------------------------------------------------
1 | default:
2 | suites:
3 | default:
4 | contexts:
5 | - FeatureContext
6 |
--------------------------------------------------------------------------------
/src/Tool/Behat/Resources/templates/drupal/FeatureContext.php.twig:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Tool/PhpCs/Resources/templates/ruleset-reference.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | Project ruleset
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Tool/PhpCs/Resources/templates/ruleset.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | Enforce coding standards
4 |
5 |
6 |
7 | {% if shouldIgnoreSomeLocationsCompletely %}
8 |
9 | {{ ignoredLocation }}
10 | {% endif %}
11 |
12 | {% if useCustomizedLineLengthSettings %}
13 | {{ include('snippet-line-length.xml.twig') }}
14 | {% endif %}
15 |
16 | {% if beLessStrictAboutDocblocksInTests %}
17 | {{ include('snippet-ignore-function-comments-in-tests.xml.twig') }}
18 | {% endif %}
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Tool/PhpCs/Resources/templates/snippet-line-length.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Tool/PhpMd/Configurator/PhpMdConfigurator.php:
--------------------------------------------------------------------------------
1 | ask(
28 | QuestionFactory::createYesOrNo('Would you like to use PHP Mess Detector?', YesOrNoAnswer::YES)
29 | );
30 | if ($usePhpMd->is(YesOrNoAnswer::NO)) {
31 | return; //do nothing
32 | }
33 |
34 | $taskDirectory->registerTask(new InstallComposerDevDependencyTask('phpmd/phpmd', '^2.0'));
35 |
36 | $project = $taskDirectory->getProject();
37 | $configurationFilesLocation = $project->getConfigurationFilesLocation();
38 |
39 | $phpMdConfiguration = $taskHelperSet->renderTemplate('phpmd-default.xml.twig', ['project' => $project]);
40 | $taskDirectory->registerTask(
41 | new WriteFileTask($configurationFilesLocation->getDirectory() . 'phpmd.xml', $phpMdConfiguration)
42 | );
43 |
44 | $antBuildSnippet = $taskHelperSet->renderTemplate(
45 | 'ant-build.xml.twig',
46 | ['targetName' => PhpMd::ANT_TARGET, 'suffixes' => ['php']]
47 | );
48 | $taskDirectory->registerTask(
49 | new AddAntBuildTask(
50 | Build::main(),
51 | Tool::withIdentifier('phpmd'),
52 | Snippet::withContentsAndTargetName($antBuildSnippet, PhpMd::ANT_TARGET)
53 | )
54 | );
55 | }
56 |
57 | public function getToolClassName()
58 | {
59 | return PhpMd::class;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Tool/PhpMd/PhpMd.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Tool/PhpMd/Resources/templates/phpmd-default.xml.twig:
--------------------------------------------------------------------------------
1 | {# @var project \Ibuildings\QaTools\Core\Project\Project #}
2 |
3 |
10 |
11 | Ibuildings QA Tools Default Ruleset for {{ project.name|escape('xml') }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/Tool/PhpParallelLint/PhpParallelLint.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Tool/PhpParallelLint/Resources/templates/ant-full.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Tool/PhpUnit/PhpUnit.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Tool/PhpUnit/Resources/templates/drupal8/bootstrap.php.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | tests
17 |
18 |
19 |
20 |
21 |
22 | src
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/Tool/PhpUnit/Resources/templates/phpunit.default.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | tests
16 |
17 |
18 |
19 |
20 |
21 | src
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/Tool/PhpUnit/Resources/templates/phpunit.symfony.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | tests
18 |
19 |
20 |
21 |
22 |
23 | src
24 |
25 | src/*Bundle/Resources
26 | src/*/*Bundle/Resources
27 | src/*/Bundle/*Bundle/Resources
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Tool/SensioLabsSecurityChecker/Configurator/SecurityCheckerConfigurator.php:
--------------------------------------------------------------------------------
1 | ask(
26 | QuestionFactory::createYesOrNo(
27 | 'Would you like to check for vulnerable dependencies using SensioLabs Security Checker?',
28 | YesOrNoAnswer::YES
29 | )
30 | );
31 |
32 | /** @var YesOrNoAnswer $useSecurityChecker */
33 | if ($useSecurityChecker->is(false)) {
34 | return;
35 | }
36 |
37 | $taskDirectory->registerTask(new InstallComposerDevDependencyTask('sensiolabs/security-checker', '^3.0'));
38 |
39 | $antSnippet = $taskHelperSet->renderTemplate(
40 | 'ant-build.xml.twig',
41 | ['targetName' => SensioLabsSecurityChecker::ANT_TARGET]
42 | );
43 |
44 | $taskDirectory->registerTask(
45 | new AddAntBuildTask(
46 | Build::main(),
47 | Tool::withIdentifier(SensioLabsSecurityChecker::ANT_TARGET),
48 | Snippet::withContentsAndTargetName($antSnippet, SensioLabsSecurityChecker::ANT_TARGET)
49 | )
50 | );
51 | }
52 |
53 | public function getToolClassName()
54 | {
55 | return SensioLabsSecurityChecker::class;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Tool/SensioLabsSecurityChecker/Resources/config/configurators.yml:
--------------------------------------------------------------------------------
1 | services:
2 | qa_tools.tool.configurator.security_checker:
3 | class: Ibuildings\QaTools\Tool\SensioLabsSecurityChecker\Configurator\SecurityCheckerConfigurator
4 | tags:
5 | - name: qa_tools.tool
6 | project_type: 'php.sf2'
7 | - name: qa_tools.tool
8 | project_type: 'php.sf3'
9 | - name: qa_tools.tool
10 | project_type: 'php.drupal7'
11 | - name: qa_tools.tool
12 | project_type: 'php.drupal8'
13 | - name: qa_tools.tool
14 | project_type: 'php.other'
15 |
--------------------------------------------------------------------------------
/src/Tool/SensioLabsSecurityChecker/Resources/templates/ant-build.xml.twig:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Tool/SensioLabsSecurityChecker/SensioLabsSecurityChecker.php:
--------------------------------------------------------------------------------
1 | container = $container;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tests/integration/Core/Templating/TemplateEngineTest.php:
--------------------------------------------------------------------------------
1 | container->get('twig.environment');
18 |
19 | $engine = new TemplateEngine($twig);
20 | $engine->setPath('../tests/integration/Core/Templating/templates');
21 |
22 | $this->expectException(Twig_Error_Runtime::class);
23 | $this->expectExceptionMessage('Variable "variableDoesNotExist" does not exist in ');
24 | $engine->render('non-existent-variable.twig', []);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/integration/Core/Templating/templates/non-existent-variable.twig:
--------------------------------------------------------------------------------
1 | This {{ variableDoesNotExist }}.
2 |
--------------------------------------------------------------------------------
/tests/integration/Core/Tool/AbstractToolTest.php:
--------------------------------------------------------------------------------
1 | build($containerBuilder);
21 |
22 | $resourcePath = $containerBuilder->getParameter('tool.' . Hammer::class . '.resource_path');
23 | $this->assertStringStartsNotWith(
24 | '/',
25 | $resourcePath,
26 | 'Resource path is an Unix-style absolute path. It must be a relative path.'
27 | );
28 | $this->assertLessThanOrEqual(
29 | 1,
30 | substr_count($resourcePath, '..'),
31 | 'Resource path should not traverse up out of the QA Tools project directory structure'
32 | );
33 | $this->assertFileExists(__DIR__ . '/../../../../bin/' . $resourcePath);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/integration/Core/Tool/Hammer/Hammer.php:
--------------------------------------------------------------------------------
1 | 1) {
24 | printf("\e[31;31mFound %d SHA384 hashes in README.md, expected only 1\e[0m\n", count($regexResults[1]));
25 | exit(1);
26 | }
27 |
28 | if ($shaOfInstaller !== $regexResults[1][0]) {
29 | echo <<120. Fail when >150"
21 | answer "Would you like to skip any sniffs regarding the doc blocks in tests?" with "n"
22 | answer "Would you like PHPCS to ignore some locations completely? (you may use a regex to match multiple directories)" with "n"
23 |
24 | answer "Would you like to check for vulnerable dependencies using SensioLabs Security Checker?" with "n"
25 | answer "Would you like to install Behat?" with "n"
26 |
27 | give_tasks_time_to_run
28 |
29 | exits_with 0
30 |
--------------------------------------------------------------------------------
/tests/system/specs/005_can-configure-a-drupal8-project.php:
--------------------------------------------------------------------------------
1 | /)" with "qa-tools/test-package"
21 | accept_default_for "Description \[\]:"
22 | answer "Author \[" with "n"
23 | accept_default_for "Minimum Stability \[\]:"
24 | accept_default_for "Package Type"
25 | accept_default_for "License \[\]:"
26 | answer "Would you like to define your dependencies (require) interactively" with "no"
27 | answer "Would you like to define your dev dependencies (require-dev) interactively" with "no"
28 | accept_default_for "Do you confirm generation"
29 |
30 | give_tasks_time_to_run
31 |
32 | exits_with 0
33 |
--------------------------------------------------------------------------------
/tests/system/specs/050_can-install-git-pre-commit-hook.php:
--------------------------------------------------------------------------------
1 | equals($other);
27 | }
28 | return false;
29 | }
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/unit/Core/Assert/AssertionTest.php:
--------------------------------------------------------------------------------
1 | expectException(InvalidArgumentException::class);
32 |
33 | Assertion::nonEmptyString($value, 'Expected non-empty string for "%3$s", got "%s" of type "%s"', 'value');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/unit/Core/Composer/PackageVersionConstraintTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($a->equals($b), $this->diff($a, $b, 'Package version constraints ought to be equal'));
27 | }
28 |
29 | public function equalConstraints()
30 | {
31 | return [
32 | '^3.1.1 == ^3.1.1' => ['^3.1.1', '^3.1.1',],
33 | '^3.1 == ^3.1.0' => ['^3.1', '^3.1.0',],
34 | '1.0 == 1.0' => ['1.0', '1.0',],
35 | '1.0 == 1.0.0' => ['1.0', '1.0.0',],
36 | 'dev-master == dev-master' => ['dev-master', 'dev-master',],
37 | ];
38 | }
39 |
40 | /**
41 | * @test
42 | * @dataProvider unequalConstraints
43 | * @param string $stringA
44 | * @param string $stringB
45 | */
46 | public function constraints_can_not_be_equal($stringA, $stringB)
47 | {
48 | $a = PackageVersionConstraint::parse($stringA);
49 | $b = PackageVersionConstraint::parse($stringB);
50 | $this->assertFalse($a->equals($b), $this->diff($a, $b, 'Package version constraints ought not to be equal'));
51 | }
52 |
53 | public function unequalConstraints()
54 | {
55 | return [
56 | '^3.1.1 != ~3.1.1' => ['^3.1.1', '~3.1.1',],
57 | '1 != 2' => ['1', '2',],
58 | 'dev-master != dev-develop' => ['dev-master', 'dev-develop',],
59 | '* != 1.0' => ['*', '1.0',],
60 | ];
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/unit/Core/Configuration/ConfiguratorRepositoryTest.php:
--------------------------------------------------------------------------------
1 | add(new FakeConfigurator(FooTool::class), new ProjectType('php.sf2'));
20 | }
21 |
22 | /** @test */
23 | public function two_configurators_for_two_different_tools_can_be_registered_under_the_same_project_type()
24 | {
25 | $registry = new ConfiguratorRepository();
26 | $registry->add(new FakeConfigurator(FooTool::class), new ProjectType('php.drupal8'));
27 | $registry->add(new FakeConfigurator(BarTool::class), new ProjectType('php.drupal8'));
28 | }
29 |
30 | /** @test */
31 | public function the_same_configurator_can_be_registered_under_two_different_project_types()
32 | {
33 | $registry = new ConfiguratorRepository();
34 |
35 | $configurator = new FakeConfigurator(FooTool::class);
36 | $registry->add($configurator, new ProjectType('php.other'));
37 | $registry->add($configurator, new ProjectType('php.drupal7'));
38 | }
39 |
40 | /** @test */
41 | public function two_configurators_for_the_same_tool_can_not_be_registered_under_the_same_project_type()
42 | {
43 | $this->expectException(LogicException::class);
44 | $this->expectExceptionMessage('same tool');
45 |
46 | $registry = new ConfiguratorRepository();
47 | $registry->add(new FakeConfigurator(FooTool::class), new ProjectType('js.angular1'));
48 | $registry->add(new FakeConfigurator(FooTool::class), new ProjectType('js.angular1'));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/unit/Core/Configuration/FakeConfigurator.php:
--------------------------------------------------------------------------------
1 | toolClassName = $toolClassName;
17 | }
18 |
19 | public function configure(Interviewer $interviewer, TaskDirectory $taskDirectory, TaskHelperSet $taskHelperSet)
20 | {
21 | }
22 |
23 | public function getToolClassName()
24 | {
25 | return $this->toolClassName;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/unit/Core/Configuration/InMemoryConfigurationRepositoryTest.php:
--------------------------------------------------------------------------------
1 | assertFalse($repository->configurationExists(), 'Repository should not have configuration in memory');
20 | }
21 |
22 | /** @test */
23 | public function stores_configuration()
24 | {
25 | $configuration = Configuration::create();
26 |
27 | $repository = new InMemoryConfigurationRepository();
28 | $repository->save($configuration);
29 |
30 | $this->assertTrue($repository->configurationExists(), 'Repository should have configuration in memory');
31 | $this->assertSame(
32 | $configuration,
33 | $repository->load(),
34 | 'Repository should have the same configuration in memory'
35 | );
36 | }
37 |
38 | /** @test */
39 | public function throws_an_exception_when_attempting_to_load_nonexistent_configuration()
40 | {
41 | $repository = new InMemoryConfigurationRepository();
42 |
43 | $this->expectException(RuntimeException::class);
44 | $this->expectExceptionMessage('No configuration stored in memory');
45 | $repository->load();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/unit/Core/Configuration/InMemoryTaskDirectoryTest.php:
--------------------------------------------------------------------------------
1 | assertCount(
28 | 0,
29 | $taskDirectory->getTasks(),
30 | 'Task directory ought to contain no registered tasks'
31 | );
32 | }
33 |
34 | /**
35 | * @test
36 | */
37 | public function the_project_given_during_instantiation_can_be_retrieved_from_the_task_directory()
38 | {
39 | $dummyProject = Mockery::mock(Project::class);
40 |
41 | $taskDirectory = new InMemoryTaskDirectory($dummyProject);
42 |
43 | $retrievedProject = $taskDirectory->getProject();
44 |
45 | $this->assertEquals($dummyProject, $retrievedProject);
46 | }
47 |
48 | /**
49 | * @test
50 | */
51 | public function a_task_can_be_registered()
52 | {
53 | $dummyProject = Mockery::mock(Project::class);
54 |
55 | $fakeTask = new NoopTask('Some task');
56 |
57 | $taskDirectory = new InMemoryTaskDirectory($dummyProject);
58 | $taskDirectory->registerTask($fakeTask);
59 |
60 | $this->assertTrue(
61 | $taskDirectory->getTasks()->equals(new TaskList([$fakeTask])),
62 | 'Task directory ought to contain the registered task'
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tests/unit/Core/Configuration/TaskHelperSetTest.php:
--------------------------------------------------------------------------------
1 | expectException(InvalidArgumentException::class);
21 |
22 | $dummyTemplateEngine = Mockery::mock(TemplateEngine::class);
23 |
24 | $taskHelperSet = new TaskHelperSet($dummyTemplateEngine);
25 | $taskHelperSet->setTemplatePath($path);
26 | }
27 |
28 | /**
29 | * @test
30 | */
31 | public function a_template_path_can_be_set()
32 | {
33 | $dummyTemplateEngine = Mockery::mock(TemplateEngine::class);
34 |
35 | $path = 'some/file/path';
36 |
37 | $dummyTemplateEngine
38 | ->shouldReceive('setPath')
39 | ->with($path);
40 |
41 | $taskHelperSet = new TaskHelperSet($dummyTemplateEngine);
42 | $taskHelperSet->setTemplatePath($path);
43 | }
44 |
45 | /**
46 | * @test
47 | *
48 | * @dataProvider \Ibuildings\QaTools\UnitTest\TestDataProvider::notStringOrEmptyString
49 | */
50 | public function a_template_that_can_be_rendered_can_only_be_a_string($template)
51 | {
52 | $this->expectException(InvalidArgumentException::class);
53 |
54 | $dummyTemplateEngine = Mockery::mock(TemplateEngine::class);
55 |
56 | $taskHelperSet = new TaskHelperSet($dummyTemplateEngine);
57 | $taskHelperSet->renderTemplate($template);
58 | }
59 |
60 | /**
61 | * @test
62 | */
63 | public function a_template_is_rendered()
64 | {
65 | $dummyTemplateEngine = Mockery::mock(TemplateEngine::class);
66 |
67 | $template = 'some/file/path';
68 |
69 | $dummyTemplateEngine
70 | ->shouldReceive('render')
71 | ->with($template, []);
72 |
73 | $taskHelperSet = new TaskHelperSet($dummyTemplateEngine);
74 | $taskHelperSet->renderTemplate($template);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/tests/unit/Core/IO/Cli/InterviewerTest.php:
--------------------------------------------------------------------------------
1 | expectException(InvalidArgumentException::class);
28 |
29 | $interviewer = new Interviewer(
30 | new ArgvInput,
31 | new DummyOutput,
32 | new QuestionHelper,
33 | new ConsoleQuestionFactory(new ConsoleQuestionFormatter)
34 | );
35 |
36 | $interviewer->notice($nonString);
37 | }
38 |
39 | /**
40 | * @test
41 | *
42 | * @dataProvider \Ibuildings\QaTools\UnitTest\TestDataProvider::notString
43 | */
44 | public function interviewer_can_only_warn_with_sentences_that_are_strings($nonString)
45 | {
46 | $this->expectException(InvalidArgumentException::class);
47 |
48 | $interviewer = new Interviewer(
49 | new ArgvInput,
50 | new DummyOutput,
51 | new QuestionHelper,
52 | new ConsoleQuestionFactory(new ConsoleQuestionFormatter)
53 | );
54 |
55 | $interviewer->warn($nonString);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/unit/Core/IO/Cli/Validator/TextualAnswerValidatorTest.php:
--------------------------------------------------------------------------------
1 | expectException(InvalidArgumentException::class);
31 |
32 | TextualAnswerValidator::validate($answer);
33 | }
34 |
35 | /**
36 | * @test
37 | *
38 | * @dataProvider \Ibuildings\QaTools\UnitTest\TestDataProvider::emptyString
39 | */
40 | public function validator_sees_empty_or_emptyish_strings_as_invalid_answers($answer)
41 | {
42 | $this->expectException(InvalidAnswerGivenException::class);
43 |
44 | TextualAnswerValidator::validate($answer);
45 | }
46 |
47 | /**
48 | * @test
49 | */
50 | public function validator_sees_null_as_invalid_answers()
51 | {
52 | $this->expectException(InvalidAnswerGivenException::class);
53 |
54 | TextualAnswerValidator::validate(null);
55 | }
56 |
57 | /**
58 | * @test
59 | */
60 | public function validator_passes_through_answers_that_are_non_empty_strings()
61 | {
62 | $answer = 'An answer';
63 |
64 | $validatedAnswer = TextualAnswerValidator::validate($answer);
65 |
66 | $this->assertEquals($answer, $validatedAnswer);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/unit/Core/Interviewer/Answer/AnswerFactoryTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($expectedAnswer, $actualAnswer);
29 | }
30 |
31 | /**
32 | * @test
33 | */
34 | public function factory_creates_a_negative_yes_or_no_answer()
35 | {
36 | $expectedAnswer = YesOrNoAnswer::no();
37 | $actualAnswer = AnswerFactory::createFrom(false);
38 |
39 | $this->assertEquals($expectedAnswer, $actualAnswer);
40 | }
41 |
42 | /**
43 | * @test
44 | */
45 | public function factory_creates_a_textual_answer()
46 | {
47 | $answerText = 'Test answer.';
48 | $expectedAnswer = new TextualAnswer($answerText);
49 | $actualAnswer = AnswerFactory::createFrom($answerText);
50 |
51 | $this->assertEquals($expectedAnswer, $actualAnswer);
52 | }
53 |
54 | /**
55 | * @test
56 | */
57 | public function factory_creates_choices()
58 | {
59 | $answerTexts = ['Test answer.', 'Another test answer'];
60 | $expectedAnswer = new Choices(
61 | [
62 | new TextualAnswer($answerTexts[0]),
63 | new TextualAnswer($answerTexts[1]),
64 | ]
65 | );
66 |
67 | $actualAnswer = AnswerFactory::createFrom($answerTexts);
68 |
69 | $this->assertEquals($expectedAnswer, $actualAnswer);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/unit/Core/Interviewer/Answer/NoDefaultAnswerTest.php:
--------------------------------------------------------------------------------
1 | assertNull($noDefaultAnswer->getRaw());
24 | }
25 |
26 | /**
27 | * @test
28 | */
29 | public function no_default_answer_does_not_equal_answer_of_other_type()
30 | {
31 | $noDefaultAnswer = new NoDefaultAnswer();
32 | $otherAnswer = new TextualAnswer('Test');
33 |
34 | $this->assertFalse($noDefaultAnswer->equals($otherAnswer));
35 | }
36 |
37 | /**
38 | * @test
39 | */
40 | public function no_default_answer_equals_another_missing_answer()
41 | {
42 | $noDefaultAnswer = new NoDefaultAnswer();
43 | $sameAnswer = new NoDefaultAnswer();
44 |
45 | $this->assertTrue($noDefaultAnswer->equals($sameAnswer));
46 | }
47 |
48 | /**
49 | * @test
50 | */
51 | public function no_default_answer_is_converted_to_an_empty_string()
52 | {
53 | $noDefaultAnswer = new NoDefaultAnswer();
54 |
55 | $this->assertEquals('', $noDefaultAnswer->convertToString());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/unit/Core/Interviewer/Answer/TextualAnswerTest.php:
--------------------------------------------------------------------------------
1 | expectException(InvalidArgumentException::class);
24 |
25 | new TextualAnswer($value);
26 | }
27 |
28 | /**
29 | * @test
30 | */
31 | public function textual_answer_does_not_equal_another_answer()
32 | {
33 | $answer = new TextualAnswer('The answer.');
34 | $otherAnswer = new TextualAnswer('Another answer.');
35 |
36 | $this->assertFalse($answer->equals($otherAnswer));
37 | }
38 |
39 | /**
40 | * @test
41 | */
42 | public function textual_answer_equals_another_answer()
43 | {
44 | $answer = new TextualAnswer('The answer.');
45 | $otherAnswer = new TextualAnswer('The answer.');
46 |
47 | $this->assertTrue($answer->equals($otherAnswer));
48 | }
49 |
50 | /**
51 | * @test
52 | */
53 | public function textual_answer_has_an_textual_answer_value()
54 | {
55 | $expectedValue = 'An answer.';
56 | $answer = new TextualAnswer($expectedValue);
57 |
58 | $actualValue = $answer->getRaw();
59 |
60 | $this->assertEquals($actualValue, $expectedValue);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/unit/Core/Interviewer/Answer/YesOrNoAnswerTest.php:
--------------------------------------------------------------------------------
1 | assertFalse($answer->equals($differentAnswer));
24 | }
25 |
26 | /**
27 | * @test
28 | */
29 | public function yes_or_no_answer_equals_the_same_yes_or_no_answer()
30 | {
31 | $answer = YesOrNoAnswer::yes();
32 | $sameAnswer = YesOrNoAnswer::yes();
33 |
34 | $this->assertTrue($answer->equals($sameAnswer));
35 | }
36 |
37 | /**
38 | * @test
39 | */
40 | public function yes_or_no_answer_has_an_answer_value()
41 | {
42 | $answer = YesOrNoAnswer::yes();
43 |
44 | $actualValue = $answer->getRaw();
45 |
46 | $this->assertTrue($actualValue);
47 | }
48 |
49 | /**
50 | * @test
51 | */
52 | public function yes_or_no_answer_created_as_yes_is_yes()
53 | {
54 | $answer = YesOrNoAnswer::yes();
55 |
56 | $this->assertTrue($answer->is(YesOrNoAnswer::YES));
57 | }
58 |
59 | /**
60 | * @test
61 | */
62 | public function yes_or_no_answer_created_as_no_is_no()
63 | {
64 | $answer = YesOrNoAnswer::no();
65 |
66 | $this->assertTrue($answer->is(YesOrNoAnswer::NO));
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/unit/Core/Project/DirectoryTest.php:
--------------------------------------------------------------------------------
1 | assertSame($directoryString, $directory->getDirectory());
24 | }
25 |
26 | /**
27 | * @test
28 | * @dataProvider equalDirectories
29 | * @param string $a
30 | * @param string $b
31 | */
32 | public function can_equal_another_directory($a, $b)
33 | {
34 | $dirA = new Directory($a);
35 | $dirB = new Directory($b);
36 |
37 | $this->assertTrue(
38 | $dirA->equals($dirB),
39 | $this->diff($a, $b, 'Directories were expected to equal')
40 | );
41 | }
42 |
43 | public function equalDirectories()
44 | {
45 | return [
46 | '/abc == /abc' => ['/abc', '/abc'],
47 | './ == ./' => ['./', './'],
48 | 'vendor/. == vendor' => ['vendor/.', 'vendor'],
49 | './vendor == vendor' => ['./vendor', 'vendor'],
50 | 'rel\\ative == rel/ative' => ['rel\\ative', 'rel/ative'],
51 | './vendor/./psr == vendor/psr' => ['./vendor/./psr', 'vendor/psr'],
52 | '/./abc == /abc/./' => ['/./abc', '/abc/./'],
53 | '/./abc/.. == /abc/./..' => ['/./abc/..', '/abc/./../'],
54 | ];
55 | }
56 |
57 | /** @test */
58 | public function can_not_equal_another_directory()
59 | {
60 | $this->assertFalse((new Directory(' ./'))->equals(new Directory(' ./vendor')));
61 | $this->assertFalse((new Directory(' ../'))->equals(new Directory(' ./')));
62 | }
63 |
64 | /** @test */
65 | public function a_relative_directory_can_be_subtracted()
66 | {
67 |
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/unit/Core/Project/ProjectTypeTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(
18 | (new ProjectType(ProjectType::TYPE_PHP_DRUPAL_8))->equals(new ProjectType(ProjectType::TYPE_PHP_DRUPAL_8)),
19 | 'Two equal project types should be equal'
20 | );
21 | }
22 |
23 | /** @test */
24 | public function must_be_one_of_the_recognised_types()
25 | {
26 | $this->expectException(InvalidArgumentException::class);
27 | $this->expectExceptionMessage('is not an element of the valid values');
28 |
29 | new ProjectType('ruby.ror');
30 | }
31 |
32 | /** @test */
33 | public function can_be_created_from_a_human_readable_string()
34 | {
35 | $this->assertTrue(
36 | ProjectType::fromHumanReadableString('Symfony 3')->equals(new ProjectType(ProjectType::TYPE_PHP_SF_3)),
37 | 'Project type created from human readable string ought to equal project type created from constant'
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/unit/Core/Task/NoopTask.php:
--------------------------------------------------------------------------------
1 | assertTrue($a->equals($b), $this->diff($a, $b, 'A ought to equal B'));
19 | *
20 | * @param mixed $expected
21 | * @param mixed $actual
22 | * @param string $title
23 | * @return string
24 | */
25 | protected function diff($expected, $actual, $title)
26 | {
27 | Assertion::string($title, 'Diff title ought to be a string, got "%s" of type "%s"');
28 |
29 | $differ = new Differ();
30 | $exporter = new Exporter();
31 |
32 | $diff = $differ->diff($exporter->export($expected), $exporter->export($actual));
33 |
34 | return sprintf("%s\n\n%s\n", $title, $diff);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/unit/InstallComposerDevDependencyTaskMatcher.php:
--------------------------------------------------------------------------------
1 | getPackageName() === $expected;
21 | }
22 | );
23 | }
24 |
25 | /**
26 | * @param string $expectedPackage
27 | * @param string $expectedVersion
28 | * @return Mockery\Matcher\Closure
29 | */
30 | public static function forVersionOf($expectedPackage, $expectedVersion)
31 | {
32 | return Mockery::on(
33 | function (Task $task) use ($expectedPackage, $expectedVersion) {
34 | return $task instanceof InstallComposerDevDependencyTask
35 | && $task->getPackageName() === $expectedPackage
36 | && $task->getPackageVersionConstraint() == $expectedVersion;
37 | }
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/unit/PharUpdater/Strategy/no-releases.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/tests/unit/ValueObject.php:
--------------------------------------------------------------------------------
1 | equals($expected)) {
18 | Assert::assertEquals($expected, $actual, "Value object don't equal each other");
19 | }
20 |
21 | return true;
22 | });
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/unit/WriteFileTaskMatcher.php:
--------------------------------------------------------------------------------
1 | getFilePath() === $expectedPath
22 | && $task->getFileContents() === $expectedContent;
23 | }
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tools/build-phar.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | &1', $installOutput)) {
6 | error("Something went wrong while installing the production dependencies:");
7 | debug($installOutput);
8 | exit(1);
9 | }
10 |
11 | // Increase open file limit
12 | // See https://github.com/box-project/box2/issues/80#issuecomment-76630852
13 | execute('command -v ulimit 2>/dev/null', $ulimit);
14 | if ($ulimit) {
15 | info("Building distributable with increased file descriptor limit...");
16 | $buildSucceeded = execute("$ulimit -Sn 4096 && composer build --ansi 2>&1", $buildOutput);
17 | } else {
18 | $buildSucceeded = execute("composer build --ansi 2>&1", $buildOutput);
19 | }
20 |
21 | if (!$buildSucceeded) {
22 | error("Something went wrong while building the distributable:");
23 | debug($buildOutput);
24 | }
25 |
26 | info("Restoring development dependencies...");
27 | if (!execute("composer install --ansi 2>&1", $installOutput)) {
28 | error("Something went wrong while restoring the development dependencies:");
29 | debug($installOutput);
30 | }
31 |
32 | exit($buildSucceeded ? 0 : 1);
33 |
34 | function debug($message) {
35 | fprintf(STDERR, "%s\n", $message);
36 | }
37 | function info($message) {
38 | fprintf(STDERR, "%s%s%s\n", "\033[33m", $message, "\033[0m");
39 | }
40 | function error($message) {
41 | fprintf(STDERR, "%s%s%s\n", "\033[41m", $message, "\033[0m");
42 | }
43 |
44 | /**
45 | * @param string $command
46 | * @param string &$stdout
47 | * @return bool Whether the process exited with exit code 0
48 | */
49 | function execute($command, &$stdout) {
50 | exec($command, $output, $exitCode);
51 | $stdout = join("\n", $output);
52 |
53 | return $exitCode === 0;
54 | }
55 |
--------------------------------------------------------------------------------
/tools/git/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Absolute path to this script, e.g. /path/to/pre-commit.bash
4 | SCRIPT=$(readlink -f "$0")
5 | # Absolute path this script is in, thus /path/to
6 | SCRIPTPATH=$(dirname "$SCRIPT")
7 |
8 | (cd $SCRIPTPATH/../.. && make test-fast)
9 |
--------------------------------------------------------------------------------
/tools/git/pre-commit-install:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Absolute path to this script, e.g. /path/to/pre-commit-install
4 | SCRIPT=$(readlink -f "$0")
5 | # Absolute path this script is in, thus /path/to
6 | SCRIPTPATH=$(dirname "$SCRIPT")
7 |
8 | ln -is $SCRIPTPATH/pre-commit $SCRIPTPATH/../../.git/hooks/pre-commit
9 | echo "Pre-commit hook installed!"
10 |
--------------------------------------------------------------------------------
/tools/git/pre-push:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Absolute path to this script, e.g. /path/to/pre-push
4 | SCRIPT=$(readlink -f "$0")
5 | # Absolute path this script is in, thus /path/to
6 | SCRIPTPATH=$(dirname "$SCRIPT")
7 |
8 | (cd $SCRIPTPATH/../.. && make test)
9 |
--------------------------------------------------------------------------------
/tools/git/pre-push-install:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Absolute path to this script, e.g. /path/to/pre-push-install
4 | SCRIPT=$(readlink -f "$0")
5 | # Absolute path this script is in, thus /path/to
6 | SCRIPTPATH=$(dirname "$SCRIPT")
7 |
8 | ln -is $SCRIPTPATH/pre-push $SCRIPTPATH/../../.git/hooks/pre-push
9 | echo "Pre-push hook installed!"
10 |
--------------------------------------------------------------------------------
/var/cache/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ibuildingsnl/qa-tools/0c4999a74c55b03a826e1c881f75ee3fba6329f7/var/cache/.gitkeep
--------------------------------------------------------------------------------
/var/composer/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------