diff --git a/.travis.yml b/.travis.yml index e48eacb0d..98456efc6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ --- language: php +os: [ linux ] + +version: ~> 1.0 + php: "7.2" addons: @@ -27,7 +31,7 @@ env: - ORCA_PACKAGES_CONFIG_ALTER=example/tests/packages_alter.yml - ORCA_SUT_DIR=${TRAVIS_BUILD_DIR}/../example -matrix: +jobs: fast_finish: true include: - { name: "Static code analysis", env: ORCA_JOB=STATIC_CODE_ANALYSIS } diff --git a/bin/pipelines/packages_alter.yml b/bin/pipelines/packages_alter.yml index 34ee6fa23..d568733b4 100644 --- a/bin/pipelines/packages_alter.yml +++ b/bin/pipelines/packages_alter.yml @@ -1,4 +1,11 @@ --- acquia/lightning: type: drupal-profile - version_dev: "*" + version: ~3.0 + +# Let Lightning manage its own components. +drupal/lightning_api: ~ +drupal/lightning_core: ~ +drupal/lightning_layout: ~ +drupal/lightning_media: ~ +drupal/lightning_workflow: ~ diff --git a/bin/travis/after_failure.sh b/bin/travis/after_failure.sh index 85e6e0de7..196a600d5 100755 --- a/bin/travis/after_failure.sh +++ b/bin/travis/after_failure.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # NAME -# after_failure.sh - Display debugging information in case of build failure. +# after_failure.sh - Display debugging information. # # SYNOPSIS # after_failure.sh # # DESCRIPTION -# Displays Drupal error log. +# Displays debugging information in case of failure. cd "$(dirname "$0")" || exit; source _includes.sh diff --git a/bin/travis/after_script.sh b/bin/travis/after_script.sh index 0242cac78..3af29e531 100755 --- a/bin/travis/after_script.sh +++ b/bin/travis/after_script.sh @@ -14,9 +14,10 @@ cd "$(dirname "$0")" || exit; source _includes.sh # Log the job on cron if telemetry is enabled. if [[ "$TRAVIS_EVENT_TYPE" = "cron" && "$ORCA_TELEMETRY_ENABLE" && "$ORCA_AMPLITUDE_API_KEY" && "$ORCA_AMPLITUDE_USER_ID" ]]; then orca internal:log-job + orca internal:log-job --simulate fi # Show ORCA's own current build status. A failure may signify an upstream issue # or service level outage that could have affected this build. # @see https://travis-ci.org/acquia/orca/branches -travis history --no-interactive --repo=acquia/orca --branch=master --limit=1 --date +echo && travis history --no-interactive --repo=acquia/orca --branch=master --limit=2 --date diff --git a/bin/travis/before_install.sh b/bin/travis/before_install.sh index c71db9611..486fe97cf 100755 --- a/bin/travis/before_install.sh +++ b/bin/travis/before_install.sh @@ -43,8 +43,10 @@ composer global require \ # Install Travis command line client. gem install travis -# Install ORCA. -composer -d"$ORCA_ROOT" install +# Download and install ORCA libraries if necessary. This provides compatibility +# with the old method of installing ORCA via `git clone` rather than the newer +# `composer create-project` approach. +[[ -d "$ORCA_ROOT/vendor" ]] || composer -d"$ORCA_ROOT" install orca --version diff --git a/bin/travis/before_script.sh b/bin/travis/before_script.sh index 4d31131c6..9b11d595d 100755 --- a/bin/travis/before_script.sh +++ b/bin/travis/before_script.sh @@ -7,8 +7,7 @@ # before_script.sh # # DESCRIPTION -# Displays information about installed Composer packages and Drupal -# projects. +# Displays details about the fixture for debugging purposes. cd "$(dirname "$0")" || exit; source _includes.sh diff --git a/bin/travis/install.sh b/bin/travis/install.sh index 6b919eb6a..8b7531b2b 100755 --- a/bin/travis/install.sh +++ b/bin/travis/install.sh @@ -7,7 +7,7 @@ # install.sh # # DESCRIPTION -# Creates the test fixture. +# Creates the test fixture and places the SUT. cd "$(dirname "$0")" || exit; source _includes.sh diff --git a/composer.json b/composer.json index a25d01c1e..8f8b35e91 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "acquia/orca", - "description": "A tool for testing all of Acquia's software packages together in the context of a realistic, functioning, best practices Drupal build", + "description": "A tool for testing a company's software packages together in the context of a realistic, functioning, best practices Drupal build", "license": "GPL-2.0-or-later", "authors": [ { diff --git a/config/VERSION b/config/VERSION index 0f1acbd56..79127d85a 100644 --- a/config/VERSION +++ b/config/VERSION @@ -1 +1 @@ -v1.1.2 +v1.2.0 diff --git a/config/packages.yml b/config/packages.yml index 96339fb3d..7aff4dd4c 100644 --- a/config/packages.yml +++ b/config/packages.yml @@ -1,5 +1,5 @@ --- -# An array of Acquia software package data. Each package datum is keyed by its +# An array of company software package data. Each package datum is keyed by its # package name, i.e., the "name" property in its composer.json file, e.g., # "drupal/example", and has a corresponding array value that may contain the # following key-value pairs: @@ -40,8 +40,6 @@ # config/services.yml for the relevant code or bin/self-test for a usage # example. -#drupal/acquia_commercemanager: [] - drupal/acquia_connector: version_dev: 1.x-dev <2.0 @@ -55,8 +53,6 @@ drupal/acquia_lift: drupal/acquia_purge: [] -#drupal/acquia_search_solr: [] - drupal/acsf: [] acquia/blt: @@ -69,8 +65,6 @@ acquia/coding-standards: drupal/cog: type: drupal-theme -#drupal/cog_tools: [] - acquia/drupal-spec-tool: type: behat-extension @@ -152,4 +146,6 @@ drupal/lightning_workflow: version: ~ version_dev: ~ +drupal/mautic: [] + drupal/media_acquiadam: [] diff --git a/config/services.yml b/config/services.yml index a0062741a..8d9dba635 100644 --- a/config/services.yml +++ b/config/services.yml @@ -7,6 +7,7 @@ parameters: env(ORCA_FIXTURE_DIR): "%app.fixture_dir%" env(ORCA_PACKAGES_CONFIG): config/packages.yml env(ORCA_PACKAGES_CONFIG_ALTER): ~ + env(ORCA_PHPCS_STANDARD): "AcquiaDrupalTransitional" env(ORCA_TELEMETRY_ENABLE): false services: @@ -17,6 +18,7 @@ services: bind: $amplitude_api_key: "%env(ORCA_AMPLITUDE_API_KEY)%" $amplitude_user_id: "%env(ORCA_AMPLITUDE_USER_ID)%" + $default_phpcs_standard: "%env(ORCA_PHPCS_STANDARD)%" $fixture_dir: "%env(ORCA_FIXTURE_DIR)%" $project_dir: "%kernel.project_dir%" $packages_config: "%env(ORCA_PACKAGES_CONFIG)%" diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5e3648bbb..b940e0a7d 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -30,6 +30,7 @@ [README](README.md) | [Understanding ORCA](understanding-orca.md) | [Getting Started](getting-started.md) +| [CLI Commands](commands.md) | [Advanced Usage](advanced-usage.md) | [Project Glossary](glossary.md) | [FAQ](faq.md) diff --git a/docs/README.md b/docs/README.md index d98610dd0..9ae2e7cb2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,16 +1,20 @@ # ORCA +[![Latest Stable Version](https://poser.pugx.org/acquia/orca/v/stable)](https://packagist.org/packages/acquia/orca) +[![Total Downloads](https://poser.pugx.org/acquia/orca/downloads)](https://packagist.org/packages/acquia/orca) +[![Latest Unstable Version](https://poser.pugx.org/acquia/orca/v/unstable)](https://packagist.org/packages/acquia/orca) +[![License](https://poser.pugx.org/acquia/orca/license)](https://packagist.org/packages/acquia/orca) [![Build Status](https://travis-ci.org/acquia/orca.svg?branch=master)](https://travis-ci.org/acquia/orca) -ORCA (Official Representative Customer Application) is a tool for testing Acquia software packages. It ensures their cross compatibility and correct functioning by installing all of them together into a realistic, functioning, best practices Drupal build and running automated tests on them. Its guiding design principle is to use Acquia packages as a customer would. It installs the latest recommended versions and performs no manual setup or configuration. +ORCA (Official Representative Customer Application) is a tool for testing a company's Drupal-adjacent software packages. It ensures their cross compatibility and correct functioning by installing all of them together into a realistic, functioning, best practices Drupal build and running automated tests and static code analysis on them. Its guiding design principle is to use company packages as a customer would. It installs the latest recommended versions via Composer and performs no manual setup or configuration. | What does it do? | What is the value? | | --- | --- | -| Adds all Acquia packages to a BLT project via Composer, installs them and their submodules, and runs their automated tests. | Ensures that all Acquia packages can be added to the same codebase via Composer (prevents dependency conflicts), that there are no install time or functional conflicts between them, and that they have no undeclared dependencies, and prevents regressions. | -| Adds only the package under test to a BLT project via Composer, installs it and its submodules, and runs its automated tests. | Ensures that the package under test has no undeclared dependencies on other Acquia packages and functions correctly on its own. | -| Performs the above tests with the recommended, stable versions of Acquia packages. | Ensures that the package under test still works with the versions of other software already released and in use and prevents releases of the package from disrupting the ecosystem. | -| Performs the above tests using the latest development versions of Acquia packages. | Ensures that the package under test will continue to work when new versions of other software are released and prevents changes in the ecosystem from breaking the package. Forces early awareness and collaboration between project teams and prevents rework and emergency support situations. | -| Performs the above tests using a threefold spread of Drupal core versions: the previous minor release, the current supported release, and the next minor dev version. | Ensures that the package under test still works with both supported releases of Drupal and will continue to work with the next one. | +| Adds all company packages to a BLT project via Composer, installs them and their subextensions, and runs their automated tests. | Ensures that all company packages can be added to the same codebase via Composer (prevents dependency conflicts), that there are no adverse install time or functional interactions between them, and that they have no undeclared dependencies, and prevents regressions. | +| Adds only the package under test to a BLT project via Composer, installs it and its subextensions, and runs its automated tests. | Ensures that the package under test has no undeclared dependencies on other company packages and functions correctly on its own. | +| Performs the above tests with the recommended, stable versions of company packages, Drush, and Drupal Console. | Ensures that the package under test still works with the versions of other software already released and in use and prevents releases of the package from disrupting the ecosystem. | +| Performs the above tests using the latest development versions of company packages, Drush, and Drupal Console. | Ensures that the package under test will continue to work when new versions of other software are released and prevents changes in the ecosystem from breaking the package. Forces early awareness and collaboration between project teams and prevents rework and release day emergency support situations. | +| Performs the above tests using a threefold spread of Drupal core versions: the previous minor release, the current supported release, and the next minor dev version. | Ensures that the package under test still works with both supported releases of Drupal and will continue to work when the next one drops. | | Performs static analysis of the package under test. | Ensures low level construction quality. (Prevents PHP warnings and errors, version incompatibility, etc.) | See [Continuous integration](understanding-orca.md#Continuous-integration) for exact details. @@ -19,6 +23,7 @@ See [Continuous integration](understanding-orca.md#Continuous-integration) for e * [Understanding ORCA](understanding-orca.md) * [Getting Started](getting-started.md) +* [CLI Commands](commands.md) * [Advanced Usage](advanced-usage.md) * [Project Glossary](glossary.md) * [FAQ](faq.md) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 58cc6c2aa..9f68f234d 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -18,6 +18,8 @@ These affect ORCA in all contexts. * **`ORCA_PACKAGES_CONFIG_ALTER`**: Alter the main list of packages ORCA installs in fixtures and runs tests on (add, remove, or change packages and their properties). Acceptable values are any valid path to a YAML file relative to ORCA itself, e.g., `../example/tests/packages_alter.yml`. See [`.travis.yml`](../.travis.yml) and [`example/tests/packages_alter.yml`](../example/tests/packages_alter.yml) for an example and explanation of the schema. **Note:** This option should be used conservatively as it erodes the uniformity at the heart of ORCA's _representative_ nature. +* **`ORCA_PHPCS_STANDARD`**: Change the PHP Code Sniffer standard used by the `qa:static-analysis` and `qa:fixer` commands. Acceptable values are `AcquiaPHP`, `AcquiaDrupalStrict`, and `AcquiaDrupalTransitional`. See [Acquia Coding Standards for PHP](https://packagist.org/packages/acquia/coding-standards) for details. + * **`ORCA_TELEMETRY_ENABLE`**: Set to `TRUE` to enable telemetry with Amplitude. Requires [`ORCA_AMPLITUDE_API_KEY`](#ORCA_AMPLITUDE_API_KEY) and [`ORCA_AMPLITUDE_USER_ID`](#ORCA_AMPLITUDE_USER_ID) values. On Travis CI, only takes effect for cron events. ### Travis CI scripts @@ -47,6 +49,7 @@ These affect ORCA only as invoked via the Travis CI scripts. [README](README.md) | [Understanding ORCA](understanding-orca.md) | [Getting Started](getting-started.md) +| [CLI Commands](commands.md) | **Advanced Usage** | [Project Glossary](glossary.md) | [FAQ](faq.md) diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 000000000..3f17ff5ec --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,1657 @@ +# CLI Commands + +* [`analyze`](#qastatic-analysis) +* [`backup`](#fixturebackup) +* [`core`](#debugcore-versions) +* [`deprecations`](#qadeprecated-code-scan) +* [`enexts`](#fixtureenable-extensions) +* [`fix`](#qafixer) +* [`help`](#help) +* [`init`](#fixtureinit) +* [`list`](#list) +* [`packages`](#debugpackages) +* [`phpstan`](#qadeprecated-code-scan) +* [`reset`](#fixturereset) +* [`rm`](#fixturerm) +* [`serve`](#fixturerun-server) +* [`si`](#fixtureinstall-site) +* [`st`](#fixturestatus) +* [`status`](#fixturestatus) +* [`test`](#qaautomated-tests) + +**debug:** + +* [`debug:core-versions`](#debugcore-versions) +* [`debug:packages`](#debugpackages) + +**fixture:** + +* [`fixture:backup`](#fixturebackup) +* [`fixture:enable-extensions`](#fixtureenable-extensions) +* [`fixture:init`](#fixtureinit) +* [`fixture:install-site`](#fixtureinstall-site) +* [`fixture:reset`](#fixturereset) +* [`fixture:rm`](#fixturerm) +* [`fixture:run-server`](#fixturerun-server) +* [`fixture:status`](#fixturestatus) + +**qa:** + +* [`qa:automated-tests`](#qaautomated-tests) +* [`qa:deprecated-code-scan`](#qadeprecated-code-scan) +* [`qa:fixer`](#qafixer) +* [`qa:static-analysis`](#qastatic-analysis) + +`help` +------ + +Displays help for a command + +### Usage + +* `help [--format FORMAT] [--raw] [--] []` + +The help command displays help for a given command: + + php ./bin/orca help list + +You can also output the help in other formats by using the --format option: + + php ./bin/orca help --format=xml list + +To display the list of available commands, please use the list command. + +### Arguments + +#### `command_name` + +The command name + +* Is required: no +* Is array: no +* Default: `'help'` + +### Options + +#### `--format` + +The output format (txt, xml, json, or md) + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'txt'` + +#### `--raw` + +To output raw command help + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`list` +------ + +Lists commands + +### Usage + +* `list [--raw] [--format FORMAT] [--] []` + +The list command lists all commands: + + php ./bin/orca list + +You can also display the commands for a specific namespace: + + php ./bin/orca list test + +You can also output the information in other formats by using the --format option: + + php ./bin/orca list --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + php ./bin/orca list --raw + +### Arguments + +#### `namespace` + +The namespace name + +* Is required: no +* Is array: no +* Default: `NULL` + +### Options + +#### `--raw` + +To output raw command list + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--format` + +The output format (txt, xml, json, or md) + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'txt'` + +`debug:core-versions` +--------------------- + +Provides an overview of Drupal Core versions + +### Usage + +* `debug:core-versions` +* `core` + +Provides an overview of Drupal Core versions + +### Options + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`debug:packages` +---------------- + +Displays the active packages configuration + +### Usage + +* `debug:packages []` +* `packages` + +Displays the active packages configuration + +### Arguments + +#### `core` + +A Drupal core version to target: +- PREVIOUS_RELEASE: The latest release of the previous minor version, e.g., "8.5.14" if the current minor version is 8.6 +- PREVIOUS_DEV: The development version of the previous minor version, e.g., "8.5.x-dev" +- CURRENT_RECOMMENDED: The current recommended release, e.g., "8.6.14" +- CURRENT_DEV: The current development version, e.g., "8.6.x-dev" +- NEXT_RELEASE: The next release version if available, e.g., "8.7.0-beta2" +- NEXT_DEV: The next development version, e.g., "8.7.x-dev" +- Any version string Composer understands, see https://getcomposer.org/doc/articles/versions.md + +* Is required: no +* Is array: no +* Default: `NULL` + +### Options + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:backup` +---------------- + +Backs up the test fixture + +### Usage + +* `fixture:backup [-f|--force]` +* `backup` + +Backs up the current state of the fixture, including codebase and Drupal database. + +### Options + +#### `--force|-f` + +Backup without confirmation + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:enable-extensions` +--------------------------- + +Enables all company Drupal extensions + +### Usage + +* `fixture:enable-extensions` +* `enexts` + +Enables all company Drupal extensions + +### Options + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:init` +-------------- + +Creates the test fixture + +### Usage + +* `fixture:init [-f|--force] [--sut SUT] [--sut-only] [--bare] [--core CORE] [--dev] [--profile PROFILE] [--ignore-patch-failure] [--no-sqlite] [--no-site-install] [--prefer-source] [--symlink-all]` +* `init` + +Creates a BLT-based Drupal site build, includes the system under test using Composer, optionally includes all other company packages, and installs Drupal. + +### Options + +#### `--force|-f` + +If the fixture already exists, remove it first without confirmation + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--sut` + +The system under test (SUT) in the form of its package name, e.g., "drupal/example" + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `NULL` + +#### `--sut-only` + +Add only the system under test (SUT). Omit all other non-required company packages + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--bare` + +Omit all non-required company packages + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--core` + +Change the version of Drupal core installed: +- PREVIOUS_RELEASE: The latest release of the previous minor version, e.g., "8.5.14" if the current minor version is 8.6 +- PREVIOUS_DEV: The development version of the previous minor version, e.g., "8.5.x-dev" +- CURRENT_RECOMMENDED: The current recommended release, e.g., "8.6.14" +- CURRENT_DEV: The current development version, e.g., "8.6.x-dev" +- NEXT_RELEASE: The next release version if available, e.g., "8.7.0-beta2" +- NEXT_DEV: The next development version, e.g., "8.7.x-dev" +- Any version string Composer understands, see https://getcomposer.org/doc/articles/versions.md + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'CURRENT_RECOMMENDED'` + +#### `--dev` + +Use dev versions of company packages + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--profile` + +The Drupal installation profile to use, e.g., "minimal". ("orca" is a pseudo-profile based on "minimal", with the Toolbar module enabled and Seven as the admin theme) + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'orca'` + +#### `--ignore-patch-failure` + +Do not exit on failure to apply Composer patches. (Useful for debugging failures) + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-sqlite` + +Use the default BLT database includes instead of SQLite + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-site-install` + +Do not install Drupal. Supersedes the "--profile" option + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--prefer-source` + +Force installation of non-company packages from sources when possible, including VCS information. (Company packages are always installed from source.) Useful for core and contrib work + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--symlink-all` + +Symlink all possible company packages via local path repository. Packages absent from the expected location will be installed normally + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:install-site` +---------------------- + +Installs the site + +### Usage + +* `fixture:install-site [-f|--force] [--profile PROFILE]` +* `si` + +Installs Drupal and enables company extensions. + +### Options + +#### `--force|-f` + +Install without confirmation + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--profile` + +The Drupal installation profile to use, e.g., "minimal". ("orca" is a pseudo-profile based on "testing", with the Toolbar module enabled and Seven as the admin theme) + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'orca'` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:reset` +--------------- + +Resets the test fixture + +### Usage + +* `fixture:reset [-f|--force]` +* `reset` + +Restores the original state of the fixture, including codebase and Drupal database. + +### Options + +#### `--force|-f` + +Remove without confirmation + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:rm` +------------ + +Removes the test fixture + +### Usage + +* `fixture:rm [-f|--force]` +* `rm` + +Removes the entire site build directory and Drupal database. + +### Options + +#### `--force|-f` + +Remove without confirmation + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:run-server` +-------------------- + +Runs the web server for development + +### Usage + +* `fixture:run-server` +* `serve` + +Runs the web server for development + +### Options + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`fixture:status` +---------------- + +Provides an overview of the fixture + +### Usage + +* `fixture:status` +* `status` +* `st` + +Provides an overview of the fixture + +### Options + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`qa:automated-tests` +-------------------- + +Runs automated tests + +### Usage + +* `qa:automated-tests [--sut SUT] [--sut-only] [--behat] [--phpunit] [--no-servers]` +* `test` + +Runs automated tests + +### Options + +#### `--sut` + +The system under test (SUT) in the form of its package name, e.g., "drupal/example" + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `NULL` + +#### `--sut-only` + +Run tests from only the system under test (SUT). Omit tests from all other company packages + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--behat` + +Run only PHPUnit tests + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phpunit` + +Run only Behat tests + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-servers` + +Don't run the ChromeDriver and web servers + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`qa:deprecated-code-scan` +------------------------- + +Scans for deprecated code + +### Usage + +* `qa:deprecated-code-scan [--sut SUT] [--contrib]` +* `deprecations` +* `phpstan` + +Scans for deprecated code + +### Options + +#### `--sut` + +Scan the system under test (SUT). Provide its package name, e.g., "drupal/example" + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `NULL` + +#### `--contrib` + +Scan contributed projects + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`qa:fixer` +---------- + +Fixes issues found by static analysis tools + +### Usage + +* `qa:fixer [--composer] [--phpcbf] [--phpcs-standard PHPCS-STANDARD] [--] ` +* `fix` + +Tools can be specified individually or in combination. If none are specified, all will be run. + +### Arguments + +#### `path` + +The path to fix issues in + +* Is required: yes +* Is array: no +* Default: `NULL` + +### Options + +#### `--composer` + +Run the Composer Normalizer tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phpcbf` + +Run the PHP Code Beautifier and Fixer tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phpcs-standard` + +Change the PHPCS standard used: +- AcquiaPHP: Contains sniffs applicable to all PHP projects +- AcquiaDrupalStrict: Recommended for new Drupal projects and teams familiar with Drupal coding standards +- AcquiaDrupalTransitional: A relaxed standard for legacy Drupal codebases or teams new to Drupal coding standards + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'AcquiaDrupalTransitional'` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +`qa:static-analysis` +-------------------- + +Runs static analysis tools + +### Usage + +* `qa:static-analysis [--composer] [--phpcs] [--phpcs-standard PHPCS-STANDARD] [--phplint] [--phploc] [--phpmd] [--yamllint] [--] ` +* `analyze` + +Tools can be specified individually or in combination. If none are specified, all will be run. + +### Arguments + +#### `path` + +The path to analyze + +* Is required: yes +* Is array: no +* Default: `NULL` + +### Options + +#### `--composer` + +Run the Composer validation tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phpcs` + +Run the PHP Code Sniffer tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phpcs-standard` + +Change the PHPCS standard used: +- AcquiaPHP: Contains sniffs applicable to all PHP projects +- AcquiaDrupalStrict: Recommended for new Drupal projects and teams familiar with Drupal coding standards +- AcquiaDrupalTransitional: A relaxed standard for legacy Drupal codebases or teams new to Drupal coding standards + +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Default: `'AcquiaDrupalTransitional'` + +#### `--phplint` + +Run the PHP Lint tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phploc` + +Run the PHP LOC tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--phpmd` + +Run the PHP Mess Detector tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--yamllint` + +Run the YAML Lint tool + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--help|-h` + +Display this help message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--quiet|-q` + +Do not output any message + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--verbose|-v|-vv|-vvv` + +Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--version|-V` + +Display this application version + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--ansi` + +Force ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-ansi` + +Disable ANSI output + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +#### `--no-interaction|-n` + +Do not ask any interactive question + +* Accept value: no +* Is value required: no +* Is multiple: no +* Default: `false` + +--- + +[README](README.md) +| [Understanding ORCA](understanding-orca.md) +| [Getting Started](getting-started.md) +| **CLI Commands** +| [Advanced Usage](advanced-usage.md) +| [Project Glossary](glossary.md) +| [FAQ](faq.md) +| [Contribution Guide](CONTRIBUTING.md) diff --git a/docs/faq.md b/docs/faq.md index e22d633cb..b6766c959 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -52,6 +52,7 @@ Cf. [Why doesn't ORCA enable my submodule/subtheme?](#why-doesnt-orca-enable-my- [README](README.md) | [Understanding ORCA](understanding-orca.md) | [Getting Started](getting-started.md) +| [CLI Commands](commands.md) | [Advanced Usage](advanced-usage.md) | [Project Glossary](glossary.md) | **FAQ** diff --git a/docs/getting-started.md b/docs/getting-started.md index cd907b7a7..238512b13 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -11,14 +11,14 @@ ORCA's primary use case is in a continuous integration workflow, running against pull requests and commits. It provides several scripts in `bin/travis` corresponding to Travis CI phases: -* **[`before_install.sh`](../bin/travis/before_install.sh)** prepares the environment and installs ORCA. -* **[`install.sh`](../bin/travis/install.sh)** creates the test fixture and places the system under test (SUT). +* **[`before_install.sh`](../bin/travis/before_install.sh)** configures the Travis CI environment, installs ORCA, and prepares the SUT. +* **[`install.sh`](../bin/travis/install.sh)** creates the test fixture and places the SUT. * **[`before_script.sh`](../bin/travis/before_script.sh)** displays details about the fixture for debugging purposes. -* **[`script.sh`](../bin/travis/script.sh)** runs static analysis and automated tests. +* **[`script.sh`](../bin/travis/script.sh)** runs static code analysis and automated tests. * **[`before_cache.sh`](../bin/travis/before_cache.sh)** is reserved for future use. * **[`after_success.sh`](../bin/travis/after_success.sh)** is reserved for future use. -* **[`after_failure.sh`](../bin/travis/after_failure.sh)** displays debugging information in case of job failure. -* **[`after_script.sh`](../bin/travis/after_script.sh)** is reserved for future use. +* **[`after_failure.sh`](../bin/travis/after_failure.sh)** displays debugging information in case of failure. +* **[`after_script.sh`](../bin/travis/after_script.sh)** conditionally logs the job and displays upstream ORCA status. See [`example/.travis.yml`](../example/.travis.yml) for an example Travis CI configuration. Features are explained in the comments. @@ -38,31 +38,25 @@ ORCA can also be installed and run locally for testing and development. Follow t PARENT_DIR="$HOME/Projects" ``` -1. Clone ORCA and your package(s) each into the directory, e.g.: +1. Install ORCA and clone your package(s) each into the directory, e.g.: ```bash - git clone git@github.com:acquia/orca.git "${PARENT_DIR}/orca" + composer create-project acquia/orca "${PARENT_DIR}/orca" git clone git@github.com:acquia/EXAMPLE.git "${PARENT_DIR}/EXAMPLE" ``` -1. Install ORCA with Composer, e.g.: - - ```bash - composer install --no-dev --working-dir="${PARENT_DIR}/orca" - ``` - 1. Optionally make the commandline executable globally-accessible... - Via symlink, e.g.: ```bash - ln -s path/to/orca/bin/orca /usr/local/bin/orca + ln -s /path/to/orca/bin/orca /usr/local/bin/orca ``` - Or via alias, e.g.: ```bash - alias orca="path/to/orca/bin/orca" + alias orca="/path/to/orca/bin/orca" ``` (Add this to your `.bash_profile`/`.bashrc` or equivalent to make it permanent.) @@ -71,19 +65,19 @@ ORCA can also be installed and run locally for testing and development. Follow t ```bash # Bash: - bash $(path/to/orca _completion --generate-hook) + bash $(/path/to/orca _completion --generate-hook) # Zsh: - source <(path/to/orca _completion --generate-hook) + source <(/path/to/orca _completion --generate-hook) ``` -Invoke ORCA from the terminal (`bin/orca`). Use the `--help` command option to learn more about the various commands or see how they're used in [`bin/travis/script`](../bin/travis/script). Use the `fixture:run-server` command to run the web server for local development. +Invoke ORCA from the terminal (`bin/orca`). Use the `--help` command option to learn more about the various commands or see how they're used in [`bin/travis/script.sh`](../bin/travis/script.sh). Use the `fixture:run-server` command to run the web server for local development. ## Running automated tests ### PHPUnit -ORCA has out-of-the-box support for [PHPUnit in Drupal 8](https://www.drupal.org/docs/8/phpunit) using core's configuration. Existing tests that work in Drupal should work in ORCA with no modification. [See a working example.](../example/tests/src/Unit/ExampleUnitTest.php) +ORCA has out-of-the-box support for [PHPUnit in Drupal](https://www.drupal.org/docs/8/phpunit) using core's configuration. Existing tests that work in Drupal should work in ORCA with no modification. [See a working example.](../example/tests/src/Unit/ExampleUnitTest.php) #### Behat @@ -108,17 +102,18 @@ ORCA uses tags (for Behat) and groups (for PHPUnit) to determine which tests to | Integrated tests (own) | ✓ | ✓ | | | Integrated tests (others') | | ✓ | | -The default behavior is to run a test only when the package providing it is the SUT--not when it is merely included in another package's test fixture. Any test not designated public or ignored is so treated. Such tests are referred to as "private tests". This should be considered the correct choice for most tests--particularly for features that involve little or no risk of conflict with other Acquia packages, including [isolated unit tests](http://wiki.c2.com/?UnitTestIsolation) by definition. +The default behavior is to run a test only when the package providing it is the SUT--not when it is merely included in another package's test fixture. Any test not designated public or ignored is so treated. Such tests are referred to as "private tests". This should be considered the correct choice for most tests--particularly for features that involve little or no risk of conflict with other company packages, including [isolated unit tests](glossary.md#isolated-unit-tests) by definition. -Public PHPUnit tests (`orca_public`) are _always_ run, including when testing packages other than the one providing them. (Behat has proved a source of too much instability to inflict across the board, so the default Travis CI jobs _never_ run non-SUT Behat tests.) For example, a public PHPUnit test provided by Lightning API will also be run during tests of Acquia Commerce Manager, Acquia Lift, and the rest. Public tests thus lengthen builds for _all Acquia packages_ and should be used judiciously. Reserve them for high value features with meaningful risk of being broken by other packages, and make them as fast as possible. +Public PHPUnit tests (`orca_public`) are _always_ run, including when testing packages other than the one providing them. (Behat has proved a source of too much instability to inflict across the board, so the default Travis CI jobs _never_ run non-SUT Behat tests.) In Acquia's implementation, for example, a public PHPUnit test provided by Lightning API will also be run during tests of Acquia Lift, Acquia Purge, and the rest. Public tests thus lengthen builds for _all company packages_ and should be used judiciously. Reserve them for high value features with meaningful risk of being broken by other packages, and make them as fast as possible. -Ignored tests (`orca_ignore`) are "ignored" and _never_ run by ORCA. Tests should be ignored when they depend upon setup or preconditions that ORCA doesn't provide, such as a fixture with unique dependencies or a database populated by SQL dump. Once ignored, such tests can be scripted to run apart from ORCA after custom setup. In practice, it should rarely be necessary to ignore a test, as most setup and teardown can be accomplished through [Behat hooks](http://behat.org/en/latest/user_guide/context/hooks.html) and [PHPUnit template methods](https://phpunit.de/manual/6.5/en/fixtures.html). +Ignored tests (`orca_ignore`) are "ignored" and _never_ run by ORCA. Tests should be ignored when they depend upon setup or preconditions that ORCA doesn't provide, such as a fixture with unique dependencies or a database populated by SQL dump. Once ignored, such tests can be scripted to run apart from ORCA after custom setup. In practice, it should rarely be necessary to ignore a test, as most setup and teardown can be accomplished through [PHPUnit template methods](https://phpunit.de/manual/6.5/en/fixtures.html) and [Behat hooks](http://behat.org/en/latest/user_guide/context/hooks.html). --- [README](README.md) | [Understanding ORCA](understanding-orca.md) | **Getting Started** +| [CLI Commands](commands.md) | [Advanced Usage](advanced-usage.md) | [Project Glossary](glossary.md) | [FAQ](faq.md) diff --git a/docs/glossary.md b/docs/glossary.md index 1ce7e9f09..e699b6cd7 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -7,6 +7,7 @@ * [Ignored tests](#ignored-tests) * [Integrated test](#integrated-test) * [Isolated test](#isolated-test) +* [Isolated unit tests](#isolated-unit-tests) * [Non-SUT tests](#non-sut-tests) * [ORCA](#orca) * [ORCA internals](#orca-internals) @@ -24,11 +25,11 @@ ## Bare fixture -A [test fixture](#test-fixture) that neither includes nor installs any [SUT](#sut) or other Acquia packages (except of course for BLT which is the foundation of all fixtures). +A [test fixture](#test-fixture) that neither includes nor installs any [SUT](#sut) or other company packages (except of course for BLT which is the foundation of all fixtures). ## Behat -| 'bēhat | An open source Behavior-Driven Development framework for PHP. [[Website]](http://behat.org/) ORCA automatically runs [public](#public-tests) and [private](#private-tests) Behat tests in Acquia packages using any `behat.yml` files found in their root directories. See also [ignored tests](#ignored-tests). +| 'bēhat | An open source Behavior-Driven Development framework for PHP. [[Website]](http://behat.org/) ORCA automatically runs [public](#public-tests) and [private](#private-tests) Behat tests in the SUT only using a `behat.yml` files found in its root directory if present. See also [ignored tests](#ignored-tests). ## BLT @@ -40,19 +41,23 @@ Automated tests that ORCA "ignores" and never runs. These are designated with an ## Integrated test -A test of the [SUT](#sut) in the presence of all other Acquia packages (i.e., in a [standard fixture](#standard-fixture)). [Read more in Understanding ORCA.](understanding-orca.md#automated-tests) +A test of the [SUT](#sut) in the presence of all other company packages (i.e., in a [standard fixture](#standard-fixture)). [Read more in Understanding ORCA.](understanding-orca.md#automated-tests) ## Isolated test A test of the [SUT](#sut) in the absence of other non-required packages (i.e., in a [SUT-only fixture](#sut-only-fixture)). [Read more in Understanding ORCA.](understanding-orca.md#automated-tests) +## Isolated unit tests + +Unit tests that run "in isolation", i.e., separate and apart from the application and all other units. See [Unit Test Isolation](http://wiki.c2.com/?UnitTestIsolation). + ## Non-SUT tests -Automated tests provided by Acquia packages other than the [SUT](#sut). +Automated tests provided by company packages other than the [SUT](#sut). ## ORCA -Official Representative Customer Application: a tool for testing all of Acquia's software packages together in the context of a realistic, functioning, best practices Drupal build. (You are here.) +Official Representative Customer Application: a tool for testing all of a company's software packages together in the context of a realistic, functioning, best practices Drupal build. (You are here.) ## ORCA internals @@ -60,7 +65,7 @@ ORCA may be thought of as providing two interfaces: a "porcelain" interface comp ## PHPUnit -A programmer-oriented testing framework used by Drupal. [[Website]](https://phpunit.de/) [[Drupal.org]](https://www.drupal.org/docs/8/phpunit) ORCA automatically runs [public](#public-tests) and [private](#private-tests) PHPUnit tests found in Acquia packages. See also [ignored tests](#ignored-tests). +A programmer-oriented testing framework used by Drupal. [[Website]](https://phpunit.de/) [[Drupal.org]](https://www.drupal.org/docs/8/phpunit) ORCA automatically runs [public](#public-tests) and [private](#private-tests) PHPUnit tests found in company packages. See also [ignored tests](#ignored-tests). ## Private tests @@ -68,15 +73,15 @@ Automated tests that ORCA runs only when the package that provides them is the [ ## Public tests -Automated tests that ORCA runs regardless of whether or not the package that provides them is the [SUT](#sut). These are designated with an `orca_public` tag ([Behat](#behat)) or group ([PHPUnit](#phpunit)). Public tests should be limited to those covering features at the greatest risk of being broken by the presence or action of other Acquia packages, and they should be as fast as possible since they will be run on all other Acquia packages' builds. [Read more in Designing automated tests: Tagging/grouping.](getting-started.md#tagginggrouping) +Automated tests that ORCA runs regardless of whether or not the package that provides them is the [SUT](#sut). These are designated with an `orca_public` tag ([Behat](#behat)) or group ([PHPUnit](#phpunit)). Public tests should be limited to those covering features at the greatest risk of being broken by the presence or action of other company packages, and they should be as fast as possible since they will be run on all other company packages' builds. [Read more in Designing automated tests: Tagging/grouping.](getting-started.md#tagginggrouping) ## Standard fixture -A [test fixture](#test-fixture) that includes and installs the [SUT](#sut) as well as all other Acquia packages. See also [integrated test](#integrated-test). +A [test fixture](#test-fixture) that includes and installs the [SUT](#sut) as well as all other company packages. See also [integrated test](#integrated-test). ## SUT -| so͞ot | System Under Test: in automated testing, the software that is being tested for correct operation. In ORCA, that means an Acquia package. +| so͞ot | System Under Test: in automated testing, the software that is being tested for correct operation. In ORCA, that means a company package. ## SUT tests @@ -84,17 +89,18 @@ Automated tests provided by the [SUT](#sut). ## SUT-only fixture -A [test fixture](#test-fixture) that includes and installs the [SUT](#sut) and omits all other non-required Acquia packages. See also [isolated test](#isolated-test). +A [test fixture](#test-fixture) that includes and installs the [SUT](#sut) and omits all other non-required company packages. See also [isolated test](#isolated-test). ## Test fixture -In automated testing, a test fixture is all the things we need to have in place in order to run a test and expect a particular outcome.[[cit.]](http://xunitpatterns.com/test%20fixture%20-%20xUnit.html) In the case of ORCA, that means a [BLT](#blt) project with all applicable Acquia software packages in place and Drupal installed. [Read more in Getting Started.](getting-started.md#test-fixtures) +In automated testing, a test fixture is all the things we need to have in place in order to run a test and expect a particular outcome.[[cit.]](http://xunitpatterns.com/test%20fixture%20-%20xUnit.html) In the case of ORCA, that means a [BLT](#blt) project with all applicable company software packages in place and Drupal installed. [Read more in Understanding ORCA.](understanding-orca.md#test-fixtures) --- [README](README.md) | [Understanding ORCA](understanding-orca.md) | [Getting Started](getting-started.md) +| [CLI Commands](commands.md) | [Advanced Usage](advanced-usage.md) | **Project Glossary** | [FAQ](faq.md) diff --git a/docs/understanding-orca.md b/docs/understanding-orca.md index 4bfe2e54d..98cb7248a 100644 --- a/docs/understanding-orca.md +++ b/docs/understanding-orca.md @@ -8,7 +8,7 @@ ## The basics -ORCA is a [Symfony Console](https://symfony.com/doc/current/components/console.html) application. It requires PHP, Composer, SQLite (which it uses to avoid a MySQL requirement on the host), and Git. It expects to be installed in a directory adjacent to the [system under test (SUT)](glossary.md#sut). It creates its [test fixtures](glossary.md#test-fixture) under the same parent, e.g.: +At its heart, ORCA is a [Symfony Console](https://symfony.com/doc/current/components/console.html) application. It requires PHP, Composer, SQLite (which it uses to avoid a MySQL requirement on the host), and Git. It expects to be installed in a directory adjacent to the [system under test (SUT)](glossary.md#sut). It creates its [test fixtures](glossary.md#test-fixture) under the same parent, e.g.: ``` . @@ -18,12 +18,14 @@ ORCA is a [Symfony Console](https://symfony.com/doc/current/components/console.h └── orca-build # The test fixture ``` +Note: The fixture directory can be changed at runtime via [environment variable](advanced-usage.md#ORCA_FIXTURE_DIR). + ## Test fixtures -An ORCA test fixture is comprised of a [BLT](glossary.md#blt) project with one or all Acquia software packages (as specified in [`config/packages.yml`](../config/packages.yml)) added via Composer. There are two basic kinds: +An ORCA test fixture is comprised of a [BLT](glossary.md#blt) project with one or all company software packages (as specified by default in [`config/packages.yml`](../config/packages.yml) and configurable via [environment variables](advanced-usage.md#ORCA_PACKAGES_CONFIG)) added via Composer. There are two basic kinds: -* A **standard fixture** includes and installs the SUT as well as all other Acquia packages. -* A **SUT-only fixture** includes and installs the SUT and omits all other non-required Acquia packages. +* A **standard fixture** includes and installs the SUT as well as all other company packages. +* A **SUT-only fixture** includes and installs the SUT and omits all other non-required company packages. Packages are included at one of two levels of stability: @@ -39,10 +41,8 @@ ORCA checks the SUT for low level construction defects using the following stati * [Composer validate](https://getcomposer.org/doc/03-cli.md#validate) checks `composer.json` files for validity and completeness. * [Composer normalize](https://github.com/localheinz/composer-normalize) checks `composer.json` files for consistent ordering and formatting. * [PHP Parallel Lint](https://github.com/JakubOnderka/PHP-Parallel-Lint) checks PHP files for syntax errors. -* [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) detects coding standards violations using the following rulesets: - * [Drupal Code Sniffer](https://packagist.org/packages/drupal/coder) encapsulates [Drupal coding standards](https://www.drupal.org/coding-standards ) and best practices for module development. - * [PHPCompatibility](https://github.com/PHPCompatibility/PHPCompatibility) checks for PHP cross-version compatibility with all supported language versions. - * [phpcs-security-audit](https://packagist.org/packages/pheromone/phpcs-security-audit) finds vulnerabilities and weaknesses related to security in PHP code. +* [Acquia Coding Standards for PHP](https://github.com/acquia/coding-standards-php) checks for coding standards and best practices compliance, checks for PHP cross-version compatibility with all supported language versions, and finds vulnerabilities and weaknesses related to security in PHP code. +* [PHPLOC](https://github.com/sebastianbergmann/phploc) measures the size and analyzes the structure of a PHP project, including such low level metrics as cyclomatic complexity and dependencies. ([Example.](https://github.com/sebastianbergmann/phploc#usage-examples)) * [PHP Mess Detector](https://phpmd.org/) looks for potential problems in PHP source code, such as possible bugs, suboptimal code, overcomplicated expressions, and unused parameters, methods, and properties. * The [Symfony YAML Linter](https://symfony.com/doc/current/components/yaml.html) checks YAML files for syntax errors. @@ -52,8 +52,8 @@ Static analysis requires no special setup of the SUT. ORCA tests for functional and behavioral correctness with [PHPUnit](glossary.md#phpunit) and [Behat](glossary.md#behat). -* An **integrated test** tests the SUT in the _presence_ of all other Acquia packages (i.e., in a standard fixture) to ensure that all packages can be added to the same codebase via Composer (preventing dependency conflicts), that there are no install time or functional conflicts between them, and prevents regressions. -* An **isolated test** tests the SUT in the _absence_ of other non-required packages (i.e., in a SUT-only fixture) to ensure that it has no undeclared dependencies on other packages and functions correctly on its own. +* An **integrated test** exercises the SUT in the _presence_ of all other company packages (i.e., in a standard fixture) to ensure that all packages can be added to the same codebase via Composer and that there are no install time or functional conflicts between them. +* An **isolated test** exercises the SUT in the _absence_ of other non-required packages (i.e., in a SUT-only fixture) to ensure that it has no undeclared dependencies on other packages and functions correctly on its own. See [Designing automated tests](getting-started.md#designing-automated-tests). @@ -79,6 +79,7 @@ See [Configuring Travis CI](getting-started.md#configuring-travis-ci). [README](README.md) | **Understanding ORCA** | [Getting Started](getting-started.md) +| [CLI Commands](commands.md) | [Advanced Usage](advanced-usage.md) | [Project Glossary](glossary.md) | [FAQ](faq.md) diff --git a/example/.travis.yml b/example/.travis.yml index 83d5f34c4..7a994b7b6 100644 --- a/example/.travis.yml +++ b/example/.travis.yml @@ -16,9 +16,18 @@ # # For advanced needs, # @see https://github.com/acquia/orca/blob/develop/docs/advanced-usage.md +# +# For all Travis CI build config options, +# @see https://config.travis-ci.com/ --- language: php +os: linux + +# Activate build config validation. +# @see https://docs.travis-ci.com/user/build-config-validation +version: ~> 1.0 + # The lowest version of PHP supported by all of Drupal, Acquia, and ORCA itself. # @see https://www.drupal.org/docs/8/system-requirements/php-requirements # @see https://docs.acquia.com/acquia-cloud/arch/tech-platform/ @@ -44,10 +53,11 @@ env: # This may be the destination branch of a pull request or the nearest # ancestor of a topic branch. - ORCA_SUT_BRANCH=8.x-1.x - # Specify the version of ORCA to use. Use the master branch for the latest - # release, develop for Dev/HEAD, or a tag name (e.g., v1.0.0) for a specific - # release. - - ORCA_VERSION=master + # Specify the version of ORCA to use. Use dev-master to track the latest + # release, dev-develop to track Dev/HEAD, or any other Composer version + # string. + # @see https://getcomposer.org/doc/articles/versions.md + - ORCA_VERSION=dev-master # If your package isn't in ORCA's packages.yml or conflicts with details # that are, you can modify the active packages configuration at runtime by # uncommenting the following line and specifying your own alter file. @@ -59,6 +69,12 @@ env: # @see https://github.com/acquia/orca/blob/master/docs/advanced-usage.md#ORCA_FIXTURE_PROFILE # - ORCA_FIXTURE_PROFILE=example # + # Change the PHP Code Sniffer standard used for static analysis. Acceptable + # values are "AcquiaPHP", "AcquiaDrupalStrict", and + # "AcquiaDrupalTransitional". Defaults to "AcquiaDrupalTransitional". + # @see https://github.com/acquia/orca/blob/master/docs/advanced-usage.md#ORCA_PHPCS_STANDARD + # - ORCA_PHPCS_STANDARD=AcquiaDrupalTransitional + # # To enable telemetry with Amplitude on cron runs, uncomment the following # line and set ORCA_AMPLITUDE_API_KEY in your Travis CI repository settings: # @see https://github.com/acquia/orca/blob/master/docs/advanced-usage.md#ORCA_TELEMETRY_ENABLE @@ -67,7 +83,7 @@ env: # Execution time is drastically reduced by splitting the build into multiple # concurrent jobs. -matrix: +jobs: # Mark the build as finished once the only remaining jobs are allowed to fail. fast_finish: true include: @@ -96,7 +112,7 @@ matrix: # Install ORCA and prepare the environment. before_install: - - git clone --branch ${ORCA_VERSION} --depth 1 https://github.com/acquia/orca.git ../orca + - composer create-project --no-dev acquia/orca ../orca "$ORCA_VERSION" - ../orca/bin/travis/before_install.sh # Create the test fixture and place the SUT. @@ -119,3 +135,36 @@ after_failure: ../orca/bin/travis/after_failure.sh # Perform final, post-script tasks. after_script: ../orca/bin/travis/after_script.sh + +# Get build notifications. +# @see https://docs.travis-ci.com/user/notifications +# notifications: +# slack: +# # @see https://docs.travis-ci.com/user/notifications#configuring-slack-notifications +# rooms: +# # Get this value from your Slack Travis CI app configuration and encrypt +# # it if your .travis.yml is stored in a public repository. +# # @see https://docs.travis-ci.com/user/notifications#configuring-slack-notifications +# # @see https://github.com/travis-ci/travis.rb#encrypt +# - secure: example_value_hdfgubdsifgudfbgs3453durghssecurestringidsuag34522irueg= +# # Limit to when the build changes from passing to failing or vice versa. +# on_success: change +# on_failure: change +# # Limit to the major version branches. +# if: branch = env(ORCA_SUT_BRANCH) +# email: +# # @see https://docs.travis-ci.com/user/notifications#configuring-email-notifications +# recipients: +# # Email distribution lists (groups) are preferable to individual addresses +# # so that personnel changes don't require corresponding code changes. +# # Though the online documentation doesn't explicitly mention it, this +# # value can also be encrypted if your .travis.yml is stored in a public +# # repository, e.g.: +# # @code travis encrypt username@example.com +# # @see https://github.com/travis-ci/travis.rb#encrypt +# - secure: example_value_hdfgubdsifgudfbgs3453durghssecurestringidsuag34522irueg= +# # Limit to when the build changes from passing to failing or vice versa. +# on_success: change +# on_failure: change +# # Limit to the major version branches. +# if: branch = env(ORCA_SUT_BRANCH) diff --git a/example/README.md b/example/README.md index 63dd91fb0..eb951ca7d 100644 --- a/example/README.md +++ b/example/README.md @@ -1,3 +1,4 @@ # Example Module -The Example module illustrates how to use ORCA. +The Example module illustrates how to use ORCA to test a Drupal module. See also [Configuring Travis CI +](../docs/getting-started.md#configuring-travis-ci). diff --git a/resources/phpcs.xml b/resources/phpcs.xml index 425243c54..3ce5de1da 100644 --- a/resources/phpcs.xml +++ b/resources/phpcs.xml @@ -16,7 +16,8 @@ vendor/ var/ - + + diff --git a/src/Command/Fixture/FixtureEnableExtensionsCommand.php b/src/Command/Fixture/FixtureEnableExtensionsCommand.php index fa486d0bd..9f2dcfe70 100644 --- a/src/Command/Fixture/FixtureEnableExtensionsCommand.php +++ b/src/Command/Fixture/FixtureEnableExtensionsCommand.php @@ -3,7 +3,7 @@ namespace Acquia\Orca\Command\Fixture; use Acquia\Orca\Enum\StatusCode; -use Acquia\Orca\Fixture\AcquiaExtensionEnabler; +use Acquia\Orca\Fixture\CompanyExtensionEnabler; use Acquia\Orca\Fixture\Fixture; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -23,11 +23,11 @@ class FixtureEnableExtensionsCommand extends Command { protected static $defaultName = 'fixture:enable-extensions'; /** - * The Acquia extension enabler. + * The company extension enabler. * - * @var \Acquia\Orca\Fixture\AcquiaExtensionEnabler + * @var \Acquia\Orca\Fixture\CompanyExtensionEnabler */ - private $acquiaExtensionEnabler; + private $companyExtensionEnabler; /** * The fixture. @@ -39,13 +39,13 @@ class FixtureEnableExtensionsCommand extends Command { /** * Constructs an instance. * - * @param \Acquia\Orca\Fixture\AcquiaExtensionEnabler $acquia_extension_enabler - * The Acquia extension enabler. + * @param \Acquia\Orca\Fixture\CompanyExtensionEnabler $company_extension_enabler + * The company extension enabler. * @param \Acquia\Orca\Fixture\Fixture $fixture * The fixture. */ - public function __construct(AcquiaExtensionEnabler $acquia_extension_enabler, Fixture $fixture) { - $this->acquiaExtensionEnabler = $acquia_extension_enabler; + public function __construct(CompanyExtensionEnabler $company_extension_enabler, Fixture $fixture) { + $this->companyExtensionEnabler = $company_extension_enabler; $this->fixture = $fixture; parent::__construct(self::$defaultName); } @@ -56,7 +56,7 @@ public function __construct(AcquiaExtensionEnabler $acquia_extension_enabler, Fi protected function configure() { $this ->setAliases(['enexts']) - ->setDescription('Enables all Acquia Drupal extensions'); + ->setDescription('Enables all company Drupal extensions'); } /** @@ -69,7 +69,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { } try { - $this->acquiaExtensionEnabler->enable(); + $this->companyExtensionEnabler->enable(); } catch (\Exception $e) { $io = new SymfonyStyle($input, $output); diff --git a/src/Command/Fixture/FixtureInitCommand.php b/src/Command/Fixture/FixtureInitCommand.php index 6dbceb28a..a94b3845a 100644 --- a/src/Command/Fixture/FixtureInitCommand.php +++ b/src/Command/Fixture/FixtureInitCommand.php @@ -117,29 +117,29 @@ protected function configure() { $this ->setAliases(['init']) ->setDescription('Creates the test fixture') - ->setHelp('Creates a BLT-based Drupal site build, includes the system under test using Composer, optionally includes all other Acquia packages, and installs Drupal.') + ->setHelp('Creates a BLT-based Drupal site build, includes the system under test using Composer, optionally includes all other company packages, and installs Drupal.') // Fundamental options. ->addOption('force', 'f', InputOption::VALUE_NONE, 'If the fixture already exists, remove it first without confirmation') ->addOption('sut', NULL, InputOption::VALUE_REQUIRED, 'The system under test (SUT) in the form of its package name, e.g., "drupal/example"') - ->addOption('sut-only', NULL, InputOption::VALUE_NONE, 'Add only the system under test (SUT). Omit all other non-required Acquia packages') + ->addOption('sut-only', NULL, InputOption::VALUE_NONE, 'Add only the system under test (SUT). Omit all other non-required company packages') // Common options. - ->addOption('bare', NULL, InputOption::VALUE_NONE, 'Omit all non-required Acquia packages') + ->addOption('bare', NULL, InputOption::VALUE_NONE, 'Omit all non-required company packages') ->addOption('core', NULL, InputOption::VALUE_REQUIRED, implode(PHP_EOL, array_merge( ['Change the version of Drupal core installed:'], DrupalCoreVersion::commandHelp(), ['- Any version string Composer understands, see https://getcomposer.org/doc/articles/versions.md'] )), DrupalCoreVersion::CURRENT_RECOMMENDED) - ->addOption('dev', NULL, InputOption::VALUE_NONE, 'Use dev versions of Acquia packages') + ->addOption('dev', NULL, InputOption::VALUE_NONE, 'Use dev versions of company packages') ->addOption('profile', NULL, InputOption::VALUE_REQUIRED, 'The Drupal installation profile to use, e.g., "minimal". ("orca" is a pseudo-profile based on "minimal", with the Toolbar module enabled and Seven as the admin theme)', FixtureCreator::DEFAULT_PROFILE) // Uncommon options. ->addOption('ignore-patch-failure', NULL, InputOption::VALUE_NONE, 'Do not exit on failure to apply Composer patches. (Useful for debugging failures)') ->addOption('no-sqlite', NULL, InputOption::VALUE_NONE, 'Use the default BLT database includes instead of SQLite') ->addOption('no-site-install', NULL, InputOption::VALUE_NONE, 'Do not install Drupal. Supersedes the "--profile" option') - ->addOption('prefer-source', NULL, InputOption::VALUE_NONE, 'Force installation of non-Acquia packages from sources when possible, including VCS information. (Acquia packages are always installed from source.) Useful for core and contrib work') - ->addOption('symlink-all', NULL, InputOption::VALUE_NONE, 'Symlink all possible Acquia packages via local path repository. Packages absent from the expected location will be installed normally'); + ->addOption('prefer-source', NULL, InputOption::VALUE_NONE, 'Force installation of non-company packages from sources when possible, including VCS information. (Company packages are always installed from source.) Useful for core and contrib work') + ->addOption('symlink-all', NULL, InputOption::VALUE_NONE, 'Symlink all possible company packages via local path repository. Packages absent from the expected location will be installed normally'); } /** diff --git a/src/Command/Fixture/FixtureInstallSiteCommand.php b/src/Command/Fixture/FixtureInstallSiteCommand.php index a97dfe107..f4cc4d88d 100644 --- a/src/Command/Fixture/FixtureInstallSiteCommand.php +++ b/src/Command/Fixture/FixtureInstallSiteCommand.php @@ -61,7 +61,7 @@ protected function configure() { $this ->setAliases(['si']) ->setDescription('Installs the site') - ->setHelp('Installs Drupal and enables Acquia extensions.') + ->setHelp('Installs Drupal and enables company extensions.') ->addOption('force', 'f', InputOption::VALUE_NONE, 'Install without confirmation') ->addOption('profile', NULL, InputOption::VALUE_REQUIRED, 'The Drupal installation profile to use, e.g., "minimal". ("orca" is a pseudo-profile based on "testing", with the Toolbar module enabled and Seven as the admin theme)', FixtureCreator::DEFAULT_PROFILE); } diff --git a/src/Command/Qa/QaAutomatedTestsCommand.php b/src/Command/Qa/QaAutomatedTestsCommand.php index 37239bbc8..0b2e45201 100644 --- a/src/Command/Qa/QaAutomatedTestsCommand.php +++ b/src/Command/Qa/QaAutomatedTestsCommand.php @@ -105,7 +105,7 @@ protected function configure() { ->setAliases(['test']) ->setDescription('Runs automated tests') ->addOption('sut', NULL, InputOption::VALUE_REQUIRED, 'The system under test (SUT) in the form of its package name, e.g., "drupal/example"') - ->addOption('sut-only', NULL, InputOption::VALUE_NONE, 'Run tests from only the system under test (SUT). Omit tests from all other Acquia packages') + ->addOption('sut-only', NULL, InputOption::VALUE_NONE, 'Run tests from only the system under test (SUT). Omit tests from all other company packages') ->addOption('behat', NULL, InputOption::VALUE_NONE, 'Run only PHPUnit tests') ->addOption('phpunit', NULL, InputOption::VALUE_NONE, 'Run only Behat tests') ->addOption('no-servers', NULL, InputOption::VALUE_NONE, "Don't run the ChromeDriver and web servers"); diff --git a/src/Command/Qa/QaFixerCommand.php b/src/Command/Qa/QaFixerCommand.php index b1f8794b2..4178c7566 100644 --- a/src/Command/Qa/QaFixerCommand.php +++ b/src/Command/Qa/QaFixerCommand.php @@ -2,6 +2,7 @@ namespace Acquia\Orca\Command\Qa; +use Acquia\Orca\Enum\PhpcsStandard; use Acquia\Orca\Enum\StatusCode; use Acquia\Orca\Task\Fixer\ComposerNormalizeTask; use Acquia\Orca\Task\Fixer\PhpCodeBeautifierAndFixerTask; @@ -53,11 +54,20 @@ class QaFixerCommand extends Command { */ protected static $defaultName = 'qa:fixer'; + /** + * The default PHPCS standard. + * + * @var string + */ + private $defaultPhpcsStandard; + /** * Constructs an instance. * * @param \Acquia\Orca\Task\Fixer\ComposerNormalizeTask $composer_normalize * The Composer normalize task. + * @param string $default_phpcs_standard + * The default PHPCS standard. * @param \Symfony\Component\Filesystem\Filesystem $filesystem * The filesystem. * @param \Acquia\Orca\Task\Fixer\PhpCodeBeautifierAndFixerTask $php_code_beautifier_and_fixer @@ -65,8 +75,9 @@ class QaFixerCommand extends Command { * @param \Acquia\Orca\Task\TaskRunner $task_runner * The task runner. */ - public function __construct(ComposerNormalizeTask $composer_normalize, Filesystem $filesystem, PhpCodeBeautifierAndFixerTask $php_code_beautifier_and_fixer, TaskRunner $task_runner) { + public function __construct(ComposerNormalizeTask $composer_normalize, string $default_phpcs_standard, Filesystem $filesystem, PhpCodeBeautifierAndFixerTask $php_code_beautifier_and_fixer, TaskRunner $task_runner) { $this->composerNormalize = $composer_normalize; + $this->defaultPhpcsStandard = $default_phpcs_standard; $this->filesystem = $filesystem; $this->phpCodeBeautifierAndFixer = $php_code_beautifier_and_fixer; $this->taskRunner = $task_runner; @@ -83,7 +94,11 @@ protected function configure() { ->setHelp('Tools can be specified individually or in combination. If none are specified, all will be run.') ->addArgument('path', InputArgument::REQUIRED, 'The path to fix issues in') ->addOption('composer', NULL, InputOption::VALUE_NONE, 'Run the Composer Normalizer tool') - ->addOption('phpcbf', NULL, InputOption::VALUE_NONE, 'Run the PHP Code Beautifier and Fixer tool'); + ->addOption('phpcbf', NULL, InputOption::VALUE_NONE, 'Run the PHP Code Beautifier and Fixer tool') + ->addOption('phpcs-standard', NULL, InputOption::VALUE_REQUIRED, implode(PHP_EOL, array_merge( + ['Change the PHPCS standard used:'], + PhpcsStandard::commandHelp() + )), $this->defaultPhpcsStandard); } /** @@ -95,7 +110,13 @@ public function execute(InputInterface $input, OutputInterface $output): int { $output->writeln(sprintf('Error: No such path: %s.', $path)); return StatusCode::ERROR; } - $this->configureTaskRunner($input); + try { + $this->configureTaskRunner($input); + } + catch (\UnexpectedValueException $e) { + $output->writeln($e->getMessage()); + return StatusCode::ERROR; + } return $this->taskRunner ->setPath($path) ->run(); @@ -116,8 +137,33 @@ private function configureTaskRunner(InputInterface $input) { $this->taskRunner->addTask($this->composerNormalize); } if ($all || $phpcbf) { + $this->phpCodeBeautifierAndFixer->setStandard($this->getStandard($input)); $this->taskRunner->addTask($this->phpCodeBeautifierAndFixer); } } + /** + * Gets the PHPCS standard to use. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * The command input. + * + * @return \Acquia\Orca\Enum\PhpcsStandard + * The PHPCS standard. + */ + private function getStandard(InputInterface $input): PhpcsStandard { + $standard = $input->getOption('phpcs-standard') ?? $this->defaultPhpcsStandard; + try { + $standard = new PhpcsStandard($standard); + } + catch (\UnexpectedValueException $e) { + $error_message = sprintf('Error: Invalid value for "--phpcs-standard" option: "%s".', $standard); + if (!$input->getParameterOption('--phpcs-standard')) { + $error_message = sprintf('Error: Invalid value for $ORCA_PHPCS_STANDARD environment variable: "%s".', $standard); + } + throw new \UnexpectedValueException($error_message, NULL, $e); + } + return $standard; + } + } diff --git a/src/Command/Qa/QaStaticAnalysisCommand.php b/src/Command/Qa/QaStaticAnalysisCommand.php index 010800289..9884bffe7 100644 --- a/src/Command/Qa/QaStaticAnalysisCommand.php +++ b/src/Command/Qa/QaStaticAnalysisCommand.php @@ -2,6 +2,7 @@ namespace Acquia\Orca\Command\Qa; +use Acquia\Orca\Enum\PhpcsStandard; use Acquia\Orca\Enum\StatusCode; use Acquia\Orca\Task\StaticAnalysisTool\ComposerValidateTask; use Acquia\Orca\Task\StaticAnalysisTool\PhpCodeSnifferTask; @@ -85,11 +86,20 @@ class QaStaticAnalysisCommand extends Command { */ protected static $defaultName = 'qa:static-analysis'; + /** + * The default PHPCS standard. + * + * @var string + */ + private $defaultPhpcsStandard; + /** * Constructs an instance. * * @param \Acquia\Orca\Task\StaticAnalysisTool\ComposerValidateTask $composer_validate * The Composer validate task. + * @param string $default_phpcs_standard + * The default PHPCs standard. * @param \Symfony\Component\Filesystem\Filesystem $filesystem * The filesystem. * @param \Acquia\Orca\Task\StaticAnalysisTool\PhpCodeSnifferTask $php_code_sniffer @@ -105,8 +115,9 @@ class QaStaticAnalysisCommand extends Command { * @param \Acquia\Orca\Task\StaticAnalysisTool\YamlLintTask $yaml_lint * The YAML lint task. */ - public function __construct(ComposerValidateTask $composer_validate, Filesystem $filesystem, PhpCodeSnifferTask $php_code_sniffer, PhpLintTask $php_lint, PhpLocTask $php_loc, PhpMessDetectorTask $php_mess_detector, TaskRunner $task_runner, YamlLintTask $yaml_lint) { + public function __construct(ComposerValidateTask $composer_validate, string $default_phpcs_standard, Filesystem $filesystem, PhpCodeSnifferTask $php_code_sniffer, PhpLintTask $php_lint, PhpLocTask $php_loc, PhpMessDetectorTask $php_mess_detector, TaskRunner $task_runner, YamlLintTask $yaml_lint) { $this->composerValidate = $composer_validate; + $this->defaultPhpcsStandard = $default_phpcs_standard; $this->filesystem = $filesystem; $this->phpCodeSniffer = $php_code_sniffer; $this->phpLint = $php_lint; @@ -128,6 +139,10 @@ protected function configure() { ->addArgument('path', InputArgument::REQUIRED, 'The path to analyze') ->addOption('composer', NULL, InputOption::VALUE_NONE, 'Run the Composer validation tool') ->addOption('phpcs', NULL, InputOption::VALUE_NONE, 'Run the PHP Code Sniffer tool') + ->addOption('phpcs-standard', NULL, InputOption::VALUE_REQUIRED, implode(PHP_EOL, array_merge( + ['Change the PHPCS standard used:'], + PhpcsStandard::commandHelp() + )), $this->defaultPhpcsStandard) ->addOption('phplint', NULL, InputOption::VALUE_NONE, 'Run the PHP Lint tool') ->addOption('phploc', NULL, InputOption::VALUE_NONE, 'Run the PHP LOC tool') ->addOption('phpmd', NULL, InputOption::VALUE_NONE, 'Run the PHP Mess Detector tool') @@ -143,7 +158,13 @@ public function execute(InputInterface $input, OutputInterface $output): int { $output->writeln(sprintf('Error: No such path: %s.', $path)); return StatusCode::ERROR; } - $this->configureTaskRunner($input); + try { + $this->configureTaskRunner($input); + } + catch (\UnexpectedValueException $e) { + $output->writeln($e->getMessage()); + return StatusCode::ERROR; + } return $this->taskRunner ->setPath($path) ->run(); @@ -162,12 +183,14 @@ private function configureTaskRunner(InputInterface $input) { $phploc = $input->getOption('phploc'); $phpmd = $input->getOption('phpmd'); $yamllint = $input->getOption('yamllint'); + // If NO tasks are specified, they are ALL implied. $all = !$composer && !$phpcs && !$phplint && !$phploc && !$phpmd && !$yamllint; if ($all || $composer) { $this->taskRunner->addTask($this->composerValidate); } if ($all || $phpcs) { + $this->phpCodeSniffer->setStandard($this->getStandard($input)); $this->taskRunner->addTask($this->phpCodeSniffer); } if ($all || $phploc) { @@ -184,4 +207,28 @@ private function configureTaskRunner(InputInterface $input) { } } + /** + * Gets the PHPCS standard to use. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * The command input. + * + * @return \Acquia\Orca\Enum\PhpcsStandard + * The PHPCS standard. + */ + private function getStandard(InputInterface $input): PhpcsStandard { + $standard = $input->getOption('phpcs-standard') ?? $this->defaultPhpcsStandard; + try { + $standard = new PhpcsStandard($standard); + } + catch (\UnexpectedValueException $e) { + $error_message = sprintf('Error: Invalid value for "--phpcs-standard" option: "%s".', $standard); + if (!$input->getParameterOption('--phpcs-standard')) { + $error_message = sprintf('Error: Invalid value for $ORCA_PHPCS_STANDARD environment variable: "%s".', $standard); + } + throw new \UnexpectedValueException($error_message, NULL, $e); + } + return $standard; + } + } diff --git a/src/Enum/PhpcsStandard.php b/src/Enum/PhpcsStandard.php new file mode 100644 index 000000000..87536ea6d --- /dev/null +++ b/src/Enum/PhpcsStandard.php @@ -0,0 +1,34 @@ +isBare) { @@ -139,16 +139,16 @@ private function enableAcquiaExtensions(): void { return; } - $this->output->section('Enabling Acquia modules & themes'); + $this->output->section('Enabling company modules & themes'); $this->enableModules(); $this->enableThemes(); } /** - * Enables the Acquia modules. + * Enables the company modules. */ private function enableModules(): void { - $module_list = $this->getAcquiaExtensionList(self::TYPE_MODULE); + $module_list = $this->getCompanyExtensionList(self::TYPE_MODULE); if (!$module_list) { return; } @@ -160,10 +160,10 @@ private function enableModules(): void { } /** - * Enables the Acquia themes. + * Enables the company themes. */ private function enableThemes(): void { - $theme_list = $this->getAcquiaExtensionList(self::TYPE_THEME); + $theme_list = $this->getCompanyExtensionList(self::TYPE_THEME); if (!$theme_list) { return; } @@ -175,15 +175,15 @@ private function enableThemes(): void { } /** - * Gets the list of Acquia extensions to enable. + * Gets the list of company extensions to enable. * * @param string $extension_type * The extension type: ::TYPE_MODULE or ::TYPE_THEME. * * @return string[] - * An indexed array of Acquia extension machine names. + * An indexed array of company extension machine names. */ - private function getAcquiaExtensionList(string $extension_type): array { + private function getCompanyExtensionList(string $extension_type): array { $extension_list = []; $top_level_packages = $this->packageManager->getAll(); diff --git a/src/Fixture/FixtureCreator.php b/src/Fixture/FixtureCreator.php index 66002b67f..8c09afe6e 100644 --- a/src/Fixture/FixtureCreator.php +++ b/src/Fixture/FixtureCreator.php @@ -320,7 +320,7 @@ public function setSqlite(bool $use_sqlite): void { * Sets the symlink all flag. * * @param bool $symlink_all - * TRUE to symlink all Acquia packages or FALSE not to. + * TRUE to symlink all company packages or FALSE not to. */ public function setSymlinkAll(bool $symlink_all): void { $this->symlinkAll = $symlink_all; @@ -392,7 +392,7 @@ private function fixDefaultDependencies(): void { // via a local "path" repository. 'acquia/lightning', ], - // Other Acquia packages are only conditionally required later and should + // Other company packages are only conditionally required later and should // in no case be included up-front. $this->getUnwantedPackageList() ), $fixture_path); @@ -455,7 +455,7 @@ private function getUnwantedPackageList(): array { } /** - * Adds Acquia packages to the codebase. + * Adds company packages to the codebase. * * @throws \Acquia\Orca\Exception\OrcaException * If the SUT isn't properly installed. @@ -465,27 +465,27 @@ private function addAcquiaPackages(): void { return; } - $this->output->section('Adding Acquia packages'); + $this->output->section('Adding company packages'); $this->addTopLevelAcquiaPackages(); - $this->addAcquiaSubextensions(); - $this->commitCodeChanges('Added Acquia packages.'); + $this->addCompanySubextensions(); + $this->commitCodeChanges('Added company packages.'); } /** - * Adds the top-level Acquia packages to composer.json. + * Adds the top-level company packages to composer.json. * * @throws \Acquia\Orca\Exception\OrcaException * If the SUT isn't properly installed. */ private function addTopLevelAcquiaPackages(): void { $this->addPathRepositories(); - $this->configureComposerForTopLevelAcquiaPackages(); - $this->composerRequireTopLevelAcquiaPackages(); + $this->configureComposerForTopLevelCompanyPackages(); + $this->composerRequireTopLevelCompanyPackages(); $this->verifySut(); } /** - * Adds Composer path repositories for Acquia packages. + * Adds Composer path repositories for company packages. * * Repositories take precedence in the order specified (i.e., first match * found wins), so our overrides need to be added to the beginning in order @@ -546,9 +546,9 @@ private function addComposerExtraData(): void { } /** - * Configures Composer to install Acquia packages from source. + * Configures Composer to install company packages from source. */ - private function configureComposerForTopLevelAcquiaPackages(): void { + private function configureComposerForTopLevelCompanyPackages(): void { $packages = $this->packageManager->getAll(); if (!$packages) { @@ -578,11 +578,11 @@ private function configureComposerForTopLevelAcquiaPackages(): void { } /** - * Requires the top-level Acquia packages via Composer. + * Requires the top-level company packages via Composer. * * @throws \Acquia\Orca\Exception\OrcaException */ - private function composerRequireTopLevelAcquiaPackages(): void { + private function composerRequireTopLevelCompanyPackages(): void { $command = [ 'composer', 'require', @@ -591,7 +591,7 @@ private function composerRequireTopLevelAcquiaPackages(): void { if ($this->preferSource) { $command[] = '--prefer-source'; } - $command = array_merge($command, $this->getAcquiaPackageDependencies()); + $command = array_merge($command, $this->getCompanyPackageDependencies()); $this->processRunner->runOrcaVendorBin($command, $this->fixture->getPath()); } @@ -659,14 +659,14 @@ private function displayFailedSymlinkDebuggingInfo() { } /** - * Gets the list of Composer dependency strings for Acquia packages. + * Gets the list of Composer dependency strings for company packages. * * @return string[] - * The list of Composer dependency strings for Acquia packages. + * The list of Composer dependency strings for company packages. * * @throws \Acquia\Orca\Exception\OrcaException */ - private function getAcquiaPackageDependencies(): array { + private function getCompanyPackageDependencies(): array { $dependencies = ($this->symlinkAll) ? $this->getLocalPackages() : $this->packageManager->getAll(); if ($this->isSutOnly) { $dependencies = [$this->sut]; @@ -802,9 +802,9 @@ private function getLocalPackageVersion(Package $package): string { } /** - * Adds Acquia subextensions to the fixture. + * Adds company subextensions to the fixture. */ - private function addAcquiaSubextensions(): void { + private function addCompanySubextensions(): void { $this->configureComposerForLocalSubextensions(); $this->composerRequireSubextensions(); } @@ -892,7 +892,7 @@ private function getLocalSubextensionPackageNames(): array { } /** - * Requires the Acquia subextensions via Composer. + * Requires the company subextensions via Composer. */ private function composerRequireSubextensions(): void { $subextensions = []; @@ -1022,7 +1022,7 @@ protected function ensureDrupalSettings(): void { /** * Installs the site. * - * Installs Drupal and enables Acquia extensions. + * Installs Drupal and enables company extensions. * * @throws \Exception */ diff --git a/src/Fixture/SiteInstaller.php b/src/Fixture/SiteInstaller.php index aafe236a1..c67b891f6 100644 --- a/src/Fixture/SiteInstaller.php +++ b/src/Fixture/SiteInstaller.php @@ -11,7 +11,7 @@ use Symfony\Component\Process\Exception\ProcessFailedException; /** - * Installs a site and enables Acquia extensions. + * Installs a site and enables company extensions. */ class SiteInstaller { @@ -37,11 +37,11 @@ class SiteInstaller { private $baseProfilePath; /** - * The Acquia extension enabler. + * The company extension enabler. * - * @var \Acquia\Orca\Fixture\AcquiaExtensionEnabler + * @var \Acquia\Orca\Fixture\CompanyExtensionEnabler */ - private $acquiaExtensionEnabler; + private $companyExtensionEnabler; /** * The filesystem. @@ -95,8 +95,8 @@ class SiteInstaller { /** * Constructs an instance. * - * @param \Acquia\Orca\Fixture\AcquiaExtensionEnabler $acquia_extension_enabler - * The Acquia extension enabler. + * @param \Acquia\Orca\Fixture\CompanyExtensionEnabler $company_extension_enabler + * The company extension enabler. * @param \Symfony\Component\Filesystem\Filesystem $filesystem * The filesystem. * @param \Acquia\Orca\Fixture\Fixture $fixture @@ -108,8 +108,8 @@ class SiteInstaller { * @param \Symfony\Component\Console\Style\SymfonyStyle $output * The output decorator. */ - public function __construct(AcquiaExtensionEnabler $acquia_extension_enabler, Filesystem $filesystem, Fixture $fixture, ProcessRunner $process_runner, string $project_dir, SymfonyStyle $output) { - $this->acquiaExtensionEnabler = $acquia_extension_enabler; + public function __construct(CompanyExtensionEnabler $company_extension_enabler, Filesystem $filesystem, Fixture $fixture, ProcessRunner $process_runner, string $project_dir, SymfonyStyle $output) { + $this->companyExtensionEnabler = $company_extension_enabler; $this->filesystem = $filesystem; $this->fixture = $fixture; $this->output = $output; @@ -277,12 +277,12 @@ private function restoreBaseProfile(): void { } /** - * Enables Acquia Drupal extensions. + * Enables company Drupal extensions. * * @throws \Exception */ private function enableExtensions(): void { - $this->acquiaExtensionEnabler->enable(); + $this->companyExtensionEnabler->enable(); if (!$this->isOrcaProfile) { return; diff --git a/src/Fixture/SubextensionManager.php b/src/Fixture/SubextensionManager.php index 55e9a8661..fb61910f0 100644 --- a/src/Fixture/SubextensionManager.php +++ b/src/Fixture/SubextensionManager.php @@ -7,7 +7,7 @@ use Symfony\Component\Finder\Finder; /** - * Provide access to Acquia Drupal subextensions physically in the fixture. + * Provide access to company Drupal subextensions physically in the fixture. */ class SubextensionManager { @@ -89,7 +89,7 @@ public function initializeTopLevelExtensions(PackageManager $package_manager): v } /** - * Gets an array of all Acquia subextensions. + * Gets an array of all company subextensions. * * @return \Acquia\Orca\Fixture\Package[] * An indexed array of package objects. @@ -155,13 +155,13 @@ public function getByParent(Package $package): array { } /** - * Finds all Acquia Drupal subextension composer.json files. + * Finds all company Drupal subextension composer.json files. * * @param string $path * A path to recursively search for subextensions. * * @return \Symfony\Component\Finder\Finder|array - * A Finder query for all Acquia Drupal subextension composer.json files + * A Finder query for all company Drupal subextension composer.json files * within the given paths or an empty array if no paths are given. */ private function findSubextensionComposerJsonFiles(string $path) { diff --git a/src/Task/Fixer/PhpCodeBeautifierAndFixerTask.php b/src/Task/Fixer/PhpCodeBeautifierAndFixerTask.php index 56a6524fa..458a23617 100644 --- a/src/Task/Fixer/PhpCodeBeautifierAndFixerTask.php +++ b/src/Task/Fixer/PhpCodeBeautifierAndFixerTask.php @@ -2,6 +2,7 @@ namespace Acquia\Orca\Task\Fixer; +use Acquia\Orca\Enum\PhpcsStandard; use Acquia\Orca\Exception\TaskFailureException; use Acquia\Orca\Task\TaskBase; use Symfony\Component\Process\Exception\ProcessFailedException; @@ -11,6 +12,13 @@ */ class PhpCodeBeautifierAndFixerTask extends TaskBase { + /** + * The standard to use. + * + * @var string + */ + private $standard = PhpcsStandard::DEFAULT; + /** * {@inheritdoc} */ @@ -29,22 +37,29 @@ public function statusMessage(): string { * {@inheritdoc} */ public function execute(): void { + $this->phpcsConfigurator->prepareTemporaryConfig(new PhpcsStandard($this->standard)); try { - $this->runPhpcbf(); + $this->processRunner->runOrcaVendorBin([ + 'phpcbf', + realpath($this->getPath()), + ], $this->phpcsConfigurator->getTempDir()); } catch (ProcessFailedException $e) { throw new TaskFailureException(); } + finally { + $this->phpcsConfigurator->cleanupTemporaryConfig(); + } } /** - * Runs phpcbf. + * Sets the standard to use. + * + * @param \Acquia\Orca\Enum\PhpcsStandard $standard + * The PHPCS standard. */ - public function runPhpcbf(): void { - $this->processRunner->runOrcaVendorBin([ - 'phpcbf', - realpath($this->getPath()), - ], "{$this->projectDir}/resources"); + public function setStandard(PhpcsStandard $standard): void { + $this->standard = $standard; } } diff --git a/src/Task/PhpcsConfigurator.php b/src/Task/PhpcsConfigurator.php new file mode 100644 index 000000000..ef73b097c --- /dev/null +++ b/src/Task/PhpcsConfigurator.php @@ -0,0 +1,106 @@ +filesystem = $filesystem; + $this->projectDir = $project_dir; + } + + /** + * The temporary directory. + * + * @var string|null + */ + private $tempDir; + + /** + * Prepares the temporary config. + * + * @param \Acquia\Orca\Enum\PhpcsStandard $standard + * The PHPCS standard to use. + */ + public function prepareTemporaryConfig(PhpcsStandard $standard): void { + $this->filesystem->mkdir($this->getTempDir()); + $this->filesystem->touch($this->getTemporaryConfigFile()); + $template = file_get_contents($this->getConfigFileTemplate()); + $contents = str_replace(self::VALUE_PLACEHOLDER, $standard->getValue(), $template); + $this->filesystem->dumpFile($this->getTemporaryConfigFile(), $contents); + } + + /** + * Cleans up the temporary config. + */ + public function cleanupTemporaryConfig(): void { + $this->filesystem->remove($this->getTempDir()); + } + + /** + * Gets the temporary directory. + * + * @return string + * The temporary directory. + */ + public function getTempDir(): string { + if ($this->tempDir) { + return $this->tempDir; + } + + $path = sprintf('%s/var/cache/phpcs/%s', $this->projectDir, uniqid()); + $this->tempDir = $path; + return $this->tempDir; + } + + /** + * Gets the path to the config file template. + * + * @return string + * The path to the config file template. + */ + private function getConfigFileTemplate(): string { + return "{$this->projectDir}/resources/phpcs.xml"; + } + + /** + * Gets the path to the temporary config file. + * + * @return string + * The path to the temporary config file. + */ + private function getTemporaryConfigFile(): string { + return "{$this->getTempDir()}/phpcs.xml"; + } + +} diff --git a/src/Task/StaticAnalysisTool/PhpCodeSnifferTask.php b/src/Task/StaticAnalysisTool/PhpCodeSnifferTask.php index 8509fac81..858d7cf0e 100644 --- a/src/Task/StaticAnalysisTool/PhpCodeSnifferTask.php +++ b/src/Task/StaticAnalysisTool/PhpCodeSnifferTask.php @@ -2,7 +2,7 @@ namespace Acquia\Orca\Task\StaticAnalysisTool; -use Acquia\Orca\Enum\StatusCode; +use Acquia\Orca\Enum\PhpcsStandard; use Acquia\Orca\Exception\TaskFailureException; use Acquia\Orca\Task\TaskBase; use Symfony\Component\Process\Exception\ProcessFailedException; @@ -15,11 +15,11 @@ class PhpCodeSnifferTask extends TaskBase { public const JSON_LOG_PATH = 'var/log/phpcs.json'; /** - * The status code. + * The standard to use. * - * @var int + * @var string */ - private $status = StatusCode::OK; + private $standard = PhpcsStandard::DEFAULT; /** * {@inheritdoc} @@ -39,37 +39,35 @@ public function statusMessage(): string { * {@inheritdoc} */ public function execute(): void { + $this->phpcsConfigurator->prepareTemporaryConfig(new PhpcsStandard($this->standard)); + try { - $this->runPhpcs(); + $this->runPhpcsCommand(); } catch (ProcessFailedException $e) { - throw new TaskFailureException(); + // Swallow failure from the first run so as not to prevent the log run, + // which will fail identically, ensuring the correct exception is thrown. } - } - /** - * Runs phpcs. - */ - public function runPhpcs(): int { try { - $this->runCommand(); + $this->logResults(); } catch (ProcessFailedException $e) { - $this->status = StatusCode::ERROR; + throw new TaskFailureException(NULL, NULL, $e); + } + finally { + $this->phpcsConfigurator->cleanupTemporaryConfig(); } - $this->logResults(); - return $this->status; } /** - * Runs phpcs and sends output to the console. + * Sets the standard to use. + * + * @param \Acquia\Orca\Enum\PhpcsStandard $standard + * The PHPCS standard. */ - private function runCommand(): void { - $this->processRunner->runOrcaVendorBin([ - 'phpcs', - '-s', - realpath($this->getPath()), - ], "{$this->projectDir}/resources"); + public function setStandard(PhpcsStandard $standard): void { + $this->standard = $standard; } /** @@ -77,14 +75,25 @@ private function runCommand(): void { */ private function logResults(): void { $this->output->comment('Logging results...'); + $this->runPhpcsCommand([ + sprintf('--report-file=%s/%s', $this->projectDir, self::JSON_LOG_PATH), + ]); + } - $this->processRunner->runOrcaVendorBin([ + /** + * Runs the PHPCS command. + * + * @param array $options + * Command line options to add to the defaults. + */ + private function runPhpcsCommand(array $options = []): void { + $command = array_merge([ 'phpcs', '-s', - '--report=json', - sprintf('--report-file=%s/%s', $this->projectDir, self::JSON_LOG_PATH), + ], $options, [ realpath($this->getPath()), - ], "{$this->projectDir}/resources"); + ]); + $this->processRunner->runOrcaVendorBin($command, $this->phpcsConfigurator->getTempDir()); } } diff --git a/src/Task/TaskBase.php b/src/Task/TaskBase.php index cf334e8f7..d6db5854e 100644 --- a/src/Task/TaskBase.php +++ b/src/Task/TaskBase.php @@ -62,6 +62,13 @@ abstract class TaskBase implements TaskInterface { */ protected $output; + /** + * The PHPCS configurator. + * + * @var \Acquia\Orca\Task\PhpcsConfigurator + */ + protected $phpcsConfigurator; + /** * Constructs an instance. * @@ -73,16 +80,25 @@ abstract class TaskBase implements TaskInterface { * The fixture. * @param \Symfony\Component\Console\Style\SymfonyStyle $output * The output decorator. + * @param \Acquia\Orca\Task\PhpcsConfigurator $phpcs_configurator + * The PHPCS configurator. * @param \Acquia\Orca\Utility\ProcessRunner $process_runner * The process runner. * @param string $project_dir * The ORCA project directory. */ - public function __construct(ConfigFileOverrider $config_file_overrider, Filesystem $filesystem, Fixture $fixture, SymfonyStyle $output, ProcessRunner $process_runner, string $project_dir) { + public function __construct(ConfigFileOverrider $config_file_overrider, Filesystem $filesystem, Fixture $fixture, SymfonyStyle $output, PhpcsConfigurator $phpcs_configurator, ProcessRunner $process_runner, string $project_dir) { $this->configFileOverrider = $config_file_overrider; $this->filesystem = $filesystem; $this->fixture = $fixture; $this->output = $output; + + // @todo The injection of this service in a base class like this constitutes + // a violation of the interface segregation principle because not all of + // its children use it. This is an indication for refactoring to use + // composition instead of inheritance. + $this->phpcsConfigurator = $phpcs_configurator; + $this->processRunner = $process_runner; $this->projectDir = $project_dir; } diff --git a/tests/Command/Fixture/FixtureEnableExtensionsCommandTest.php b/tests/Command/Fixture/FixtureEnableExtensionsCommandTest.php index 65f8522c0..d12b790c5 100644 --- a/tests/Command/Fixture/FixtureEnableExtensionsCommandTest.php +++ b/tests/Command/Fixture/FixtureEnableExtensionsCommandTest.php @@ -5,19 +5,19 @@ use Acquia\Orca\Command\Fixture\FixtureEnableExtensionsCommand; use Acquia\Orca\Enum\StatusCode; use Acquia\Orca\Exception\OrcaException; -use Acquia\Orca\Fixture\AcquiaExtensionEnabler; +use Acquia\Orca\Fixture\CompanyExtensionEnabler; use Acquia\Orca\Fixture\Fixture; use Acquia\Orca\Tests\Command\CommandTestBase; use Symfony\Component\Console\Command\Command; /** - * @property \Prophecy\Prophecy\ObjectProphecy|AcquiaExtensionEnabler $acquiaModuleEnabler + * @property \Prophecy\Prophecy\ObjectProphecy|CompanyExtensionEnabler $companyExtensionEnabler * @property \Prophecy\Prophecy\ObjectProphecy|\Acquia\Orca\Fixture\Fixture $fixture */ class FixtureEnableExtensionsCommandTest extends CommandTestBase { protected function setUp() { - $this->acquiaModuleEnabler = $this->prophesize(AcquiaExtensionEnabler::class); + $this->companyExtensionEnabler = $this->prophesize(CompanyExtensionEnabler::class); $this->fixture = $this->prophesize(Fixture::class); $this->fixture->exists() ->willReturn(TRUE); @@ -26,11 +26,11 @@ protected function setUp() { } protected function createCommand(): Command { - /** @var \Acquia\Orca\Fixture\AcquiaExtensionEnabler $acquia_extension_enabler */ - $acquia_extension_enabler = $this->acquiaModuleEnabler->reveal(); + /** @var \Acquia\Orca\Fixture\CompanyExtensionEnabler $company_extension_enabler */ + $company_extension_enabler = $this->companyExtensionEnabler->reveal(); /** @var \Acquia\Orca\Fixture\Fixture $fixture */ $fixture = $this->fixture->reveal(); - return new FixtureEnableExtensionsCommand($acquia_extension_enabler, $fixture); + return new FixtureEnableExtensionsCommand($company_extension_enabler, $fixture); } /** @@ -41,11 +41,11 @@ public function testCommand($fixture_exists, $install_called, $exception, $statu ->exists() ->shouldBeCalled() ->willReturn($fixture_exists); - $this->acquiaModuleEnabler + $this->companyExtensionEnabler ->enable() ->shouldBeCalledTimes($install_called); if ($exception) { - $this->acquiaModuleEnabler + $this->companyExtensionEnabler ->enable() ->willThrow($exception); } diff --git a/tests/Command/Qa/QaFixerCommandTest.php b/tests/Command/Qa/QaFixerCommandTest.php index f82bafc4a..c76001a0a 100644 --- a/tests/Command/Qa/QaFixerCommandTest.php +++ b/tests/Command/Qa/QaFixerCommandTest.php @@ -3,6 +3,7 @@ namespace Acquia\Orca\Tests\Command\Qa; use Acquia\Orca\Command\Qa\QaFixerCommand; +use Acquia\Orca\Enum\PhpcsStandard; use Acquia\Orca\Enum\StatusCode; use Acquia\Orca\Task\Fixer\ComposerNormalizeTask; use Acquia\Orca\Task\Fixer\PhpCodeBeautifierAndFixerTask; @@ -21,6 +22,8 @@ class QaFixerCommandTest extends CommandTestBase { private const SUT_PATH = '/var/www/example'; + private $defaultPhpcsStandard = PhpcsStandard::DEFAULT; + protected function setUp() { $this->composerNormalize = $this->prophesize(ComposerNormalizeTask::class); $this->filesystem = $this->prophesize(Filesystem::class); @@ -37,7 +40,7 @@ protected function createCommand(): Command { $php_code_beautifier_and_fixer = $this->phpCodeBeautifierAndFixer->reveal(); /** @var \Acquia\Orca\Task\TaskRunner $task_runner */ $task_runner = $this->taskRunner->reveal(); - return new QaFixerCommand($composer_normalize, $filesystem, $php_code_beautifier_and_fixer, $task_runner); + return new QaFixerCommand($composer_normalize, $this->defaultPhpcsStandard, $filesystem, $php_code_beautifier_and_fixer, $task_runner); } /** @@ -114,4 +117,114 @@ public function providerTaskFiltering() { ]; } + /** + * @dataProvider providerPhpcsStandardOption + */ + public function testPhpcsStandardOption($args, $standard) { + $this->filesystem + ->exists(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn(TRUE); + $this->phpCodeBeautifierAndFixer + ->setStandard(new PhpcsStandard($standard)) + ->shouldBeCalledOnce(); + $this->taskRunner + ->addTask($this->phpCodeBeautifierAndFixer->reveal()) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->setPath(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->run() + ->shouldBeCalledOnce(); + $args['--phpcbf'] = 1; + $args['path'] = self::SUT_PATH; + + $this->executeCommand($args); + + $this->assertEquals('', $this->getDisplay(), 'Displayed correct output.'); + $this->assertEquals(StatusCode::OK, $this->getStatusCode(), 'Returned correct status code.'); + } + + public function providerPhpcsStandardOption() { + return [ + [[], $this->defaultPhpcsStandard], + [['--phpcs-standard' => PhpcsStandard::ACQUIA_PHP], PhpcsStandard::ACQUIA_PHP], + [['--phpcs-standard' => PhpcsStandard::ACQUIA_DRUPAL_TRANSITIONAL], PhpcsStandard::ACQUIA_DRUPAL_TRANSITIONAL], + [['--phpcs-standard' => PhpcsStandard::ACQUIA_DRUPAL_STRICT], PhpcsStandard::ACQUIA_DRUPAL_STRICT], + ]; + } + + /** + * @dataProvider providerPhpcsStandardEnvVar + */ + public function testPhpcsStandardEnvVar($standard) { + $this->defaultPhpcsStandard = $standard; + $this->filesystem + ->exists(self::SUT_PATH) + ->shouldBeCalledTimes(1) + ->willReturn(TRUE); + $this->phpCodeBeautifierAndFixer + ->setStandard(new PhpcsStandard($this->defaultPhpcsStandard)) + ->shouldBeCalledOnce(); + $this->taskRunner + ->addTask($this->phpCodeBeautifierAndFixer->reveal()) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->setPath(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->run() + ->shouldBeCalledOnce(); + $args = [ + '--phpcbf' => 1, + 'path' => self::SUT_PATH, + ]; + + $this->executeCommand($args); + + $this->assertEquals('', $this->getDisplay(), 'Displayed correct output.'); + $this->assertEquals(StatusCode::OK, $this->getStatusCode(), 'Returned correct status code.'); + } + + public function providerPhpcsStandardEnvVar() { + return [ + [PhpcsStandard::ACQUIA_PHP], + [PhpcsStandard::ACQUIA_DRUPAL_TRANSITIONAL], + [PhpcsStandard::ACQUIA_DRUPAL_STRICT], + ]; + } + + /** + * @dataProvider providerInvalidPhpcsStandard + */ + public function testInvalidPhpcsStandard($args, $default_standard, $display) { + $this->defaultPhpcsStandard = $default_standard; + $this->filesystem + ->exists(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn(TRUE); + $this->taskRunner + ->run() + ->shouldNotBeCalled(); + $args['--phpcbf'] = 1; + $args['path'] = self::SUT_PATH; + + $this->executeCommand($args); + + $this->assertEquals($display, $this->getDisplay(), 'Displayed correct output.'); + $this->assertEquals(StatusCode::ERROR, $this->getStatusCode(), 'Returned correct status code.'); + } + + public function providerInvalidPhpcsStandard() { + return [ + [['--phpcs-standard' => 'invalid'], $this->defaultPhpcsStandard, 'Error: Invalid value for "--phpcs-standard" option: "invalid".' . PHP_EOL], + [[], 'invalid', 'Error: Invalid value for $ORCA_PHPCS_STANDARD environment variable: "invalid".' . PHP_EOL], + ]; + } + } diff --git a/tests/Command/Qa/QaStaticAnalysisCommandTest.php b/tests/Command/Qa/QaStaticAnalysisCommandTest.php index 64d10f9cb..7a355101d 100644 --- a/tests/Command/Qa/QaStaticAnalysisCommandTest.php +++ b/tests/Command/Qa/QaStaticAnalysisCommandTest.php @@ -3,6 +3,7 @@ namespace Acquia\Orca\Tests\Command\Qa; use Acquia\Orca\Command\Qa\QaStaticAnalysisCommand; +use Acquia\Orca\Enum\PhpcsStandard; use Acquia\Orca\Enum\StatusCode; use Acquia\Orca\Task\StaticAnalysisTool\ComposerValidateTask; use Acquia\Orca\Task\StaticAnalysisTool\PhpCodeSnifferTask; @@ -29,6 +30,8 @@ class QaStaticAnalysisCommandTest extends CommandTestBase { private const SUT_PATH = '/var/www/example'; + private $defaultPhpcsStandard = PhpcsStandard::DEFAULT; + protected function setUp() { $this->composerValidate = $this->prophesize(ComposerValidateTask::class); $this->filesystem = $this->prophesize(Filesystem::class); @@ -57,7 +60,7 @@ protected function createCommand(): Command { $task_runner = $this->taskRunner->reveal(); /** @var \Acquia\Orca\Task\StaticAnalysisTool\YamlLintTask $yaml_lint */ $yaml_lint = $this->yamlLint->reveal(); - return new QaStaticAnalysisCommand($composer_validate, $filesystem, $php_code_sniffer, $php_lint, $php_loc, $php_mess_detector, $task_runner, $yaml_lint); + return new QaStaticAnalysisCommand($composer_validate, $this->defaultPhpcsStandard, $filesystem, $php_code_sniffer, $php_lint, $php_loc, $php_mess_detector, $task_runner, $yaml_lint); } /** @@ -154,4 +157,114 @@ public function providerTaskFiltering() { ]; } + /** + * @dataProvider providerPhpcsStandardOption + */ + public function testPhpcsStandardOption($args, $standard) { + $this->filesystem + ->exists(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn(TRUE); + $this->phpCodeSniffer + ->setStandard(new PhpcsStandard($standard)) + ->shouldBeCalledOnce(); + $this->taskRunner + ->addTask($this->phpCodeSniffer->reveal()) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->setPath(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->run() + ->shouldBeCalledOnce(); + $args['--phpcs'] = 1; + $args['path'] = self::SUT_PATH; + + $this->executeCommand($args); + + $this->assertEquals('', $this->getDisplay(), 'Displayed correct output.'); + $this->assertEquals(StatusCode::OK, $this->getStatusCode(), 'Returned correct status code.'); + } + + public function providerPhpcsStandardOption() { + return [ + [[], $this->defaultPhpcsStandard], + [['--phpcs-standard' => PhpcsStandard::ACQUIA_PHP], PhpcsStandard::ACQUIA_PHP], + [['--phpcs-standard' => PhpcsStandard::ACQUIA_DRUPAL_TRANSITIONAL], PhpcsStandard::ACQUIA_DRUPAL_TRANSITIONAL], + [['--phpcs-standard' => PhpcsStandard::ACQUIA_DRUPAL_STRICT], PhpcsStandard::ACQUIA_DRUPAL_STRICT], + ]; + } + + /** + * @dataProvider providerPhpcsStandardEnvVar + */ + public function testPhpcsStandardEnvVar($standard) { + $this->defaultPhpcsStandard = $standard; + $this->filesystem + ->exists(self::SUT_PATH) + ->shouldBeCalledTimes(1) + ->willReturn(TRUE); + $this->phpCodeSniffer + ->setStandard(new PhpcsStandard($this->defaultPhpcsStandard)) + ->shouldBeCalledOnce(); + $this->taskRunner + ->addTask($this->phpCodeSniffer->reveal()) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->setPath(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn($this->taskRunner); + $this->taskRunner + ->run() + ->shouldBeCalledOnce(); + $args = [ + '--phpcs' => 1, + 'path' => self::SUT_PATH, + ]; + + $this->executeCommand($args); + + $this->assertEquals('', $this->getDisplay(), 'Displayed correct output.'); + $this->assertEquals(StatusCode::OK, $this->getStatusCode(), 'Returned correct status code.'); + } + + public function providerPhpcsStandardEnvVar() { + return [ + [PhpcsStandard::ACQUIA_PHP], + [PhpcsStandard::ACQUIA_DRUPAL_TRANSITIONAL], + [PhpcsStandard::ACQUIA_DRUPAL_STRICT], + ]; + } + + /** + * @dataProvider providerInvalidPhpcsStandard + */ + public function testInvalidPhpcsStandard($args, $default_standard, $display) { + $this->defaultPhpcsStandard = $default_standard; + $this->filesystem + ->exists(self::SUT_PATH) + ->shouldBeCalledOnce() + ->willReturn(TRUE); + $this->taskRunner + ->run() + ->shouldNotBeCalled(); + $args['--phpcs'] = 1; + $args['path'] = self::SUT_PATH; + + $this->executeCommand($args); + + $this->assertEquals($display, $this->getDisplay(), 'Displayed correct output.'); + $this->assertEquals(StatusCode::ERROR, $this->getStatusCode(), 'Returned correct status code.'); + } + + public function providerInvalidPhpcsStandard() { + return [ + [['--phpcs-standard' => 'invalid'], $this->defaultPhpcsStandard, 'Error: Invalid value for "--phpcs-standard" option: "invalid".' . PHP_EOL], + [[], 'invalid', 'Error: Invalid value for $ORCA_PHPCS_STANDARD environment variable: "invalid".' . PHP_EOL], + ]; + } + } diff --git a/tests/Task/TasksTest.php b/tests/Task/TasksTest.php index 013635950..490fa6200 100644 --- a/tests/Task/TasksTest.php +++ b/tests/Task/TasksTest.php @@ -3,6 +3,7 @@ namespace Acquia\Orca\Tests\Task; use Acquia\Orca\Fixture\Fixture; +use Acquia\Orca\Task\PhpcsConfigurator; use Acquia\Orca\Task\StaticAnalysisTool\ComposerValidateTask; use Acquia\Orca\Task\StaticAnalysisTool\PhpCodeSnifferTask; use Acquia\Orca\Task\StaticAnalysisTool\PhpLintTask; @@ -29,11 +30,13 @@ public function testConstruction($class) { $fixture = $this->prophesize(Fixture::class)->reveal(); /** @var \Symfony\Component\Console\Style\SymfonyStyle $output */ $output = $this->prophesize(SymfonyStyle::class)->reveal(); + /** @var \Acquia\Orca\Task\PhpcsConfigurator $phpcs_configurator */ + $phpcs_configurator = $this->prophesize(PhpcsConfigurator::class)->reveal(); /** @var \Acquia\Orca\Utility\ProcessRunner $process_runner */ $process_runner = $this->prophesize(ProcessRunner::class)->reveal(); $project_dir = '/var/www/orca'; - $object = new $class($config_file_overrider, $filesystem, $fixture, $output, $process_runner, $project_dir); + $object = new $class($config_file_overrider, $filesystem, $fixture, $output, $phpcs_configurator, $process_runner, $project_dir); $this->assertInstanceOf($class, $object, sprintf('Successfully instantiated class: %s.', $class)); }