Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support of passing project-specific configuration to code sniffer #6

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@
"squizlabs/php_codesniffer": "dev-api-friendly as 3.x-dev",
"drupal/coder": "^8.3",
"phpmd/phpmd": "dev-api-friendly",
"phploc/phploc": "^6.0"
"phploc/phploc": "^6.0",
"symfony/console": "^5.2"
},
"require-dev": {
"clue/phar-composer": "^1.1"
},
"autoload": {
"psr-0": { "": "src/" }
},
"bin": ["src/index.php"]
}
133 changes: 133 additions & 0 deletions src/PHPDebt/Console/Command/PHPDebtCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

namespace PHPDebt\Console\Command;

use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Runner;
use PHPDebt\PHPDebtMD;
use SebastianBergmann\FinderFacade\FinderFacade;
use SebastianBergmann\PHPLOC\Analyser;
use Symfony\Component\Console\{
Command\Command,
Input\InputArgument,
Input\InputInterface,
Input\InputOption,
Output\OutputInterface
};

/**
* The class for all `phpdebt` command.
*
* @package PHPDebt\Console\Command
*/
class PHPDebtCommand extends Command {

/**
* {@inheritdoc}
*/
protected function configure() {
$this->setName('phpdebt')
->addArgument('path', InputArgument::REQUIRED, 'The path of the file or directory that needs to be scanned.')
->addOption('standard', 's', InputOption::VALUE_REQUIRED, 'The path of the phpcs.xml.dist')
->setDescription('This tool provides code quality score based on a number of standards from existing code analysis tools.');
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$code_faults = 0;
$standards_faults = 0;
$path = $input->getArgument('path');
$option = $input->getOption('standard');

$debt_md = new PHPDebtMD();
$code_faults += $debt_md->process($path, 'cleancode');
$code_faults += $debt_md->process($path, 'codesize');
$code_faults += $debt_md->process($path, 'design');
$code_faults += $debt_md->process($path, 'naming');
$code_faults += $debt_md->process($path, 'unusedcode');

$runner = new Runner();
// If PHPCS config is provided, then execute this.
if ($option) {
define('PHP_CODESNIFFER_CBF', FALSE);
$runner->config = new Config(["--standard=$option"]);
Comment on lines +53 to +55

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having this if be running phpcs in two contexts, we should move the running until after and have the if just for determining if we need a default for $option.
I mean to say:

if (!$option) {
  $option = 'sane default';
}
$runner->config = new Config(["--standard=$option"]);
...

$runner->config->files = [$path];

$runner->init();
$faults = $runner->run();
print "phpcs Drupal: " . $faults . "\n";
$standards_faults += $faults;

$faults = $runner->run();
print "phpcs DrupalPractice: " . $faults . "\n";
$standards_faults += $faults;
Comment on lines +59 to +65

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two are identical. Also the print lines should reflect $options instead of always being drupal.

}
else {
$runner->config = new Config();
$runner->config->files = [$path];
$runner->config->standards = ['Drupal'];
$runner->config->extensions = [
'php' => 'PHP',
'module' => 'PHP',
'inc' => 'PHP',
'install' => 'PHP',
'test' => 'PHP',
'profile' => 'PHP',
'theme' => 'PHP',
'css' => 'CSS',
'info' => 'PHP',
'js' => 'JS',
];
$runner->init();
$faults = $runner->run();
print "phpcs Drupal: " . $faults . "\n";
$standards_faults += $faults;

$runner->config->standards = ['DrupalPractice'];
$runner->init();
$faults = $runner->run();
print "phpcs DrupalPractice: " . $faults . "\n";
$standards_faults += $faults;
}

// Lines of Code should be working on and anything unique about getting his local back up to date?
$files = (new FinderFacade([$path], [], ['*.php', '*.module', '*.install', '*.inc', '*.js', '*.scss'], []))->findFiles();
$count = (new Analyser)->countFiles($files, TRUE);
$total_lines = $count['ncloc'];

$faults = $code_faults + $standards_faults;
$percent = ($faults / $total_lines) * 100;

// Summary
print "Total Faults: " . $faults . "\n";
print "Total Lines: " . $total_lines . "\n";
print "Quality Score: " . number_format($percent, 2) . " faults per 100 lines\n";

$ratio = 200;
$base = ($total_lines / $ratio) * sqrt($percent);

if ($percent > 25) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 25));
print "Estimate to get to 25: " . number_format($base - $hours, 2) . " hours\n";
}

if ($percent > 10) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 10));
print "Estimate to get to 10: " . number_format($base - $hours, 2) . " hours\n";
}

if ($percent > 5) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 5));
print "Estimate to get to 5: " . number_format($base - $hours, 2) . " hours\n";
}

if ($percent > 3) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 3));
print "Estimate to get to 3: " . number_format($base - $hours, 2) . " hours\n";
}
return 0;
}

}
42 changes: 42 additions & 0 deletions src/PHPDebt/PHPDebtMD.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace PHPDebt;

use PHPMD\PHPMD;
use PHPMD\RuleSetFactory;

/**
* The main facade of the PHPDebt's PHPMD application.
*
* @package PHPDebt
*/
class PHPDebtMD {

/**
* This methods does the job of returning the rule violations as per PHPMD.
*
* @param string $path
* The provided path that needs to be scanned.
* @param string $type
* The received ruleset.
*
* @return int|void
*/
public function process(string $path, string $type) {
$ruleSetFactory = new RuleSetFactory();
$phpmd = new PHPMD();

$report = $phpmd->runReport(
$path,
$type,
$ruleSetFactory
);

$faults = count($report->getRuleViolations());

print "phpmd " . $type . ": " . $faults . "\n";

return count($report->getRuleViolations());
}

}
109 changes: 8 additions & 101 deletions src/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,104 +3,11 @@
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/squizlabs/php_codesniffer/autoload.php';

use PHPMD\PHPMD;
use PHPMD\RuleSetFactory;

use SebastianBergmann\FinderFacade\FinderFacade;
use SebastianBergmann\PHPLOC\Analyser;

use PHP_CodeSniffer\Runner;
use PHP_CodeSniffer\Config;

$code_faults = 0;
$standards_faults = 0;
$path = $argv[1];

function phpMD($path, $type) {
$ruleSetFactory = new RuleSetFactory();
$phpmd = new PHPMD();

$report = $phpmd->runReport(
$path,
$type,
$ruleSetFactory
);

$faults = count($report->getRuleViolations());

print "phpmd " . $type . ": " . $faults . "\n";

return count($report->getRuleViolations());
}

$code_faults += phpMD($path, 'cleancode');
$code_faults += phpMD($path, 'codesize');
$code_faults += phpMD($path, 'design');
$code_faults += phpMD($path, 'naming');
$code_faults += phpMD($path, 'unusedcode');


$runner = new Runner();

$runner->config = new Config();
$runner->config->files = [$path];
$runner->config->standards = ['Drupal'];
$runner->config->extensions = [
'php' => 'PHP',
'module' => 'PHP',
'inc' => 'PHP',
'install' => 'PHP',
'test' => 'PHP',
'profile' => 'PHP',
'theme' => 'PHP',
'css' => 'CSS',
'info' => 'PHP',
'js' => 'JS'
];
$runner->init();

$faults = $runner->run();
print "phpcs Drupal: " . $faults . "\n";
$standards_faults += $faults;

$runner->config->standards = ['DrupalPractice'];
$runner->init();
$faults = $runner->run();
print "phpcs DrupalPractice: " . $faults . "\n";
$standards_faults += $faults;

// Lines of Code
$files = (new FinderFacade([$path], [], ['*.php', '*.module', '*.install', '*.inc', '*.js', '*.scss'], []))->findFiles();
$count = (new Analyser)->countFiles($files, true);
$total_lines = $count['ncloc'];

$faults = $code_faults + $standards_faults;
$percent = ($faults / $total_lines) * 100;

// Summary
print "Total Faults: " . $faults . "\n";
print "Total Lines: " . $total_lines . "\n";
print "Quality Score: " . number_format($percent, 2) . " faults per 100 lines\n";

$ratio = 200;
$base = ($total_lines / $ratio) * sqrt($percent);

if ($percent > 25) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 25));
print "Estimate to get to 25: " . number_format($base - $hours, 2) . " hours\n";
}

if ($percent > 10) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 10));
print "Estimate to get to 10: " . number_format($base - $hours, 2) . " hours\n";
}

if ($percent > 5) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 5));
print "Estimate to get to 5: " . number_format($base - $hours, 2) . " hours\n";
}

if ($percent > 3) {
$hours = ($total_lines / $ratio) * sqrt($percent - ($percent - 3));
print "Estimate to get to 3: " . number_format($base - $hours, 2) . " hours\n";
}
use PHPDebt\Console\Command\PHPDebtCommand;
use Symfony\Component\Console\Application;

$command = new PHPDebtCommand();
$app = new Application();
$app->add($command);
$app->setDefaultCommand($command->getName(), TRUE);
$app->run();