Skip to content

Commit 5fff83a

Browse files
plopescjustafish
andauthored
feat: Add a new phpcs command to run phpcs analysis (#28)
* Create PhpCsCommand.php * Update install.yaml * Update drupal * Update PhpCsCommand.php * Add more linting commands * Fixes to lint commands and add documentation --------- Co-authored-by: Sally Young <[email protected]>
1 parent cd06f6c commit 5fff83a

11 files changed

+301
-5
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,20 @@ a11y test for a custom admin theme
7171
```
7272
ddev nightwatch --tag a11y:admin --adminTheme seven
7373
```
74+
75+
## Core Linting
76+
77+
This will run static tests against core standards.
78+
79+
```
80+
ddev drupal lint:phpstan
81+
ddev drupal lint:phpcs
82+
ddev drupal lint:js
83+
ddev drupal lint:css
84+
ddev drupal lint:cspell
85+
# CSpell against only modified files
86+
ddev drupal lint:cspell --modified-only
87+
```
88+
89+
You can run all linting with `ddev drupal lint`, or with fail-fast turned on:
90+
`ddev drupal lint --stop-on-failure`

commands/web/drupal

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@
1515

1616
use Drupal\Core\Command\GenerateTheme;
1717
use Drupal\Core\Command\InstallCommand;
18-
use Symfony\Component\Console\Application;
19-
use DrupalCoreDev\Command\CacheCommand;
2018
use DrupalCoreDev\Command\AdminLoginCommand;
21-
use DrupalCoreDev\Command\TestCommand;
19+
use DrupalCoreDev\Command\CacheCommand;
20+
use DrupalCoreDev\Command\LintCommand;
21+
use DrupalCoreDev\Command\LintCspellCommand;
22+
use DrupalCoreDev\Command\LintCssCommand;
23+
use DrupalCoreDev\Command\LintJsCommand;
24+
use DrupalCoreDev\Command\LintPhpCsCommand;
25+
use DrupalCoreDev\Command\LintPhpStanCommand;
2226
use DrupalCoreDev\Command\TestBrowserCommand;
27+
use DrupalCoreDev\Command\TestCommand;
2328
use DrupalCoreDev\Command\UninstallCommand;
29+
use Symfony\Component\Console\Application;
2430

2531
if (PHP_SAPI !== 'cli') {
2632
return;
@@ -39,5 +45,11 @@ $application->add(new AdminLoginCommand($loader));
3945
$application->add(new TestCommand());
4046
$application->add(new TestBrowserCommand());
4147
$application->add(new UninstallCommand());
48+
$application->add(new LintPhpCsCommand());
49+
$application->add(new LintPhpStanCommand());
50+
$application->add(new LintCssCommand());
51+
$application->add(new LintJsCommand());
52+
$application->add(new LintCspellCommand());
53+
$application->add(new LintCommand());
4254

4355
$application->run();

core-dev/phpunit-chrome.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3+
# cspell:ignore ddev
34
#ddev-generated
45
-->
56
<!-- For how to customize PHPUnit configuration, see core/tests/README.md. -->
@@ -36,7 +37,7 @@
3637

3738
<!-- Deprecation testing is managed through Symfony's PHPUnit Bridge.
3839
The environment variable SYMFONY_DEPRECATIONS_HELPER is used to configure
39-
the behaviour of the deprecation tests.
40+
the behavior of the deprecation tests.
4041
See https://symfony.com/doc/current/components/phpunit_bridge.html#configuration
4142
Drupal core's testing framework is setting this variable to its defaults.
4243
Projects with their own requirements need to manage this variable

core-dev/phpunit-firefox.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3+
# cspell:ignore ddev
34
#ddev-generated
45
-->
56
<!-- For how to customize PHPUnit configuration, see core/tests/README.md. -->
@@ -36,7 +37,7 @@
3637

3738
<!-- Deprecation testing is managed through Symfony's PHPUnit Bridge.
3839
The environment variable SYMFONY_DEPRECATIONS_HELPER is used to configure
39-
the behaviour of the deprecation tests.
40+
the behavior of the deprecation tests.
4041
See https://symfony.com/doc/current/components/phpunit_bridge.html#configuration
4142
Drupal core's testing framework is setting this variable to its defaults.
4243
Projects with their own requirements need to manage this variable

core-dev/src/Command/LintCommand.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
#ddev-generated
3+
4+
namespace DrupalCoreDev\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Input\InputOption;
9+
use Symfony\Component\Console\Output\OutputInterface;
10+
use Symfony\Component\Process\Process;
11+
12+
class LintCommand extends Command {
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
protected function configure(): void {
17+
$this->setName('lint')
18+
->setDescription('Run lint tests.')
19+
->addOption('stop-on-failure', null, InputOption::VALUE_NONE, 'Stop all test execution once a failure is found.');
20+
}
21+
22+
/**
23+
* {@inheritdoc}
24+
*/
25+
protected function execute(InputInterface $input, OutputInterface $output): int {
26+
$return = 0;
27+
$stop_on_failure = $input->getOption('stop-on-failure');
28+
29+
$commands = [
30+
new LintPhpCsCommand(),
31+
new LintPhpStanCommand(),
32+
new LintCssCommand(),
33+
new LintJsCommand(),
34+
new LintCspellCommand(),
35+
];
36+
37+
foreach ($commands as $command) {
38+
$return_command = $command->execute($input, $output);
39+
if (!$return_command) {
40+
continue;
41+
}
42+
$return = $return_command;
43+
44+
if ($stop_on_failure) {
45+
return $return;
46+
}
47+
}
48+
49+
return $return;
50+
}
51+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
#ddev-generated
3+
4+
namespace DrupalCoreDev\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Input\InputOption;
9+
use Symfony\Component\Console\Output\OutputInterface;
10+
use Symfony\Component\Process\Process;
11+
12+
class LintCspellCommand extends Command {
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
protected function configure(): void {
17+
$this->setName('lint:cspell')
18+
->setDescription('Run CSpell analysis.')
19+
->addOption('modified-only', null, InputOption::VALUE_NONE, 'Only run cspell on modified files.');
20+
}
21+
22+
/**
23+
* {@inheritdoc}
24+
*/
25+
protected function execute(InputInterface $input, OutputInterface $output): int {
26+
$modified_only = $input->getOption('modified-only');
27+
$command = "cd core && yarn run spellcheck:core --no-must-find-files";
28+
if ($modified_only) {
29+
$command = "cd core && git diff --name-only | sed \"s_^_../_\" | yarn run spellcheck:core --no-must-find-files --file-list stdin";
30+
}
31+
$phpcs = Process::fromShellCommandline($command);
32+
$output->writeln($command);
33+
$phpcs->setTimeout(0);
34+
$phpcs->run(function ($type, $data) use ($output) {
35+
$output->write($data);
36+
});
37+
if ($phpcs->getExitCode()) {
38+
return 1;
39+
}
40+
return 0;
41+
}
42+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
#ddev-generated
3+
4+
namespace DrupalCoreDev\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Symfony\Component\Console\Style\SymfonyStyle;
10+
use Symfony\Component\Process\Process;
11+
12+
class LintCssCommand extends Command {
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
protected function configure(): void {
17+
$this->setName('lint:css')
18+
->setDescription('Run CSS coding standard analysis against core.');
19+
}
20+
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
protected function execute(InputInterface $input, OutputInterface $output): int {
25+
$io = new SymfonyStyle($input, $output);
26+
$yarn = getcwd() . '/core/.yarn';
27+
$node_modules = getcwd() . '/core/node_modules';
28+
29+
// Check if dependencies folder exists before to start.
30+
if(!file_exists($yarn) || !file_exists($node_modules)) {
31+
$io->error('Missing Yarn dependencies. Ensure that you run yarn install before executing this command.');
32+
return 1;
33+
}
34+
35+
$command = "cd core && yarn run lint:css --color --custom-formatter=node_modules/stylelint-formatter-gitlab";
36+
$phpcs = Process::fromShellCommandline($command);
37+
$output->writeln($command);
38+
$phpcs->setTimeout(0);
39+
$phpcs->run(function ($type, $data) use ($output) {
40+
$output->write($data);
41+
});
42+
if ($phpcs->getExitCode()) {
43+
return 1;
44+
}
45+
return 0;
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
#ddev-generated
3+
4+
namespace DrupalCoreDev\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Symfony\Component\Console\Style\SymfonyStyle;
10+
use Symfony\Component\Process\Process;
11+
12+
class LintJsCommand extends Command {
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
protected function configure(): void {
17+
$this->setName('lint:js')
18+
->setDescription('Run JS coding standard analysis against core.');
19+
}
20+
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
protected function execute(InputInterface $input, OutputInterface $output): int {
25+
$io = new SymfonyStyle($input, $output);
26+
$yarn = getcwd() . '/core/.yarn';
27+
$node_modules = getcwd() . '/core/node_modules';
28+
29+
// Check if dependencies folder exists before to start.
30+
if(!file_exists($yarn) || !file_exists($node_modules)) {
31+
$io->error('Missing Yarn dependencies. Ensure that you run yarn install before executing this command.');
32+
return 1;
33+
}
34+
35+
$command = "cd core && yarn run lint:core-js-passing";
36+
$phpcs = Process::fromShellCommandline($command);
37+
$output->writeln($command);
38+
$phpcs->setTimeout(0);
39+
$phpcs->run(function ($type, $data) use ($output) {
40+
$output->write($data);
41+
});
42+
if ($phpcs->getExitCode()) {
43+
return 1;
44+
}
45+
return 0;
46+
}
47+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
#ddev-generated
3+
4+
namespace DrupalCoreDev\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Symfony\Component\Process\Process;
10+
11+
class LintPhpCsCommand extends Command {
12+
/**
13+
* {@inheritdoc}
14+
*/
15+
protected function configure(): void {
16+
$this->setName('lint:phpcs')
17+
->setDescription('Run PHPCS coding standard analysis against core.');
18+
}
19+
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
protected function execute(InputInterface $input, OutputInterface $output): int {
24+
$command = "composer phpcs -- --report-full --report-summary";
25+
$phpcs = Process::fromShellCommandline($command);
26+
$output->writeln($command);
27+
$phpcs->setTimeout(0);
28+
$phpcs->run(function ($type, $data) use ($output) {
29+
$output->write($data);
30+
});
31+
if ($phpcs->getExitCode()) {
32+
return 1;
33+
}
34+
return 0;
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
#ddev-generated
3+
4+
namespace DrupalCoreDev\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Symfony\Component\Process\Process;
10+
11+
class LintPhpStanCommand extends Command {
12+
/**
13+
* {@inheritdoc}
14+
*/
15+
protected function configure(): void {
16+
$this->setName('lint:phpstan')
17+
->setDescription('Run PHPStan code quality analysis against core.');
18+
}
19+
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
protected function execute(InputInterface $input, OutputInterface $output): int {
24+
$command = "php vendor/bin/phpstan analyze --configuration=./core/phpstan.neon.dist --error-format=table";
25+
$phpcs = Process::fromShellCommandline($command);
26+
$output->writeln($command);
27+
$phpcs->setTimeout(0);
28+
$phpcs->run(function ($type, $data) use ($output) {
29+
$output->write($data);
30+
});
31+
if ($phpcs->getExitCode()) {
32+
return 1;
33+
}
34+
return 0;
35+
}
36+
}

install.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ project_files:
1818
- core-dev/src/Command/TestCommand.php
1919
- core-dev/src/Command/TestBrowserCommand.php
2020
- core-dev/src/Command/UninstallCommand.php
21+
- core-dev/src/Command/LintPhpCsCommand.php
22+
- core-dev/src/Command/LintPhpStanCommand.php
23+
- core-dev/src/Command/LintCssCommand.php
24+
- core-dev/src/Command/LintJsCommand.php
25+
- core-dev/src/Command/LintCspellCommand.php
26+
- core-dev/src/Command/LintCommand.php
2127

2228
post_install_actions:
2329
- cp core-dev/phpunit-chrome.xml ../core/phpunit.xml

0 commit comments

Comments
 (0)