Commit 459ca7f4 authored by Kosta Harlan's avatar Kosta Harlan
Browse files

Refactor console commands to classes taht can be reused elsewhere

parent 1aa180b2
Pipeline #213 passed with stage
## v0.2.1
- Refactor console commands to classes that can be reused elsewhere.
## v0.2.0
- Add 'suggestions:post' command
......
{
"name": "kostajh/fix-suggestions",
"version": "0.2.0",
"version": "0.2.1",
"description": "Generate and publish fix suggestions for MediaWiki core and extensions/skins. Currently for Gerrit, later for GitLab.",
"type": "library",
"require": {
......
......@@ -2,11 +2,11 @@
namespace FixSuggestions\Command;
use FixSuggestions\Generator\Gerrit;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
class GenerateFixSuggestions extends Command {
......@@ -115,54 +115,26 @@ TAG
}
// TODO: Maybe extract this block into a class once we have GitLab and/or eslint added.
if ( $input->getOption( 'code-review' ) === 'gerrit' ) {
if ( $this->shouldRunPhpcs( $input ) ) {
$response = [];
$cacheFile = sprintf( '%s/%s.json',
$input->getOption( 'cache-directory' ),
$input->getOption( 'project' ) );
$this->makeDirectoriesIfNeeded( $cacheFile );
$process = new Process( [
'vendor/bin/phpcs',
'--cache=' . $cacheFile,
'-q',
'--report=vendor/mediawiki/mediawiki-codesniffer/MediaWiki/Reports/GerritRobotComments.php',
...$input->getOption( 'files' )
],
if ( $input->getOption( 'code-review' ) === Gerrit::ID ) {
$cacheFile = sprintf( '%s/%s.json',
$input->getOption( 'cache-directory' ),
$input->getOption( 'project' ) );
$generator = new Gerrit(
$cacheFile,
$input->getOption( 'files' ),
$input->getOption( 'working-directory' ),
[
'GERRIT_ROBOT_ID' => $input->getOption( 'gerrit-robot-id' ),
'GERRIT_ROBOT_RUN_ID' => $input->getOption( 'gerrit-robot-run-id' ),
'GERRIT_URL' => $input->getOption( 'gerrit-robot-url' ),
'PHPCS_ROOT_DIR' => $input->getOption( 'working-directory' )
]
);
$process->run();
if ( $process->getExitCode() !== 2 ) {
// phpcs returns exit code 2 even when generating report properly.
$output->writeln( '<error>An error occurred:</error>' );
$output->writeln( $process->getErrorOutput() );
$output->write( $process->getOutput() );
return Command::FAILURE;
}
$outputFile = sprintf( '%s/%s/%s/phpcs.%s.json',
$input->getOption( 'output-directory' ),
$input->getOption( 'code-review' ),
$input->getOption( 'project' ),
$input->getOption( 'gerrit-robot-run-id' )
);
$this->makeDirectoriesIfNeeded( $outputFile );
file_put_contents(
$outputFile,
$process->getOutput()
);
if ( $input->getOption( 'format' ) === 'json' ) {
$response['code_review'] = $input->getOption( 'code-review' );
$response['suggestions']['phpcs'] = $outputFile;
$output->write( json_encode( $response ) );
}
return Command::SUCCESS;
$input->getOption( 'gerrit-robot-id' ),
$input->getOption( 'gerrit-robot-run-id' ),
$input->getOption( 'gerrit-robot-url' ),
$input->getOption( 'output-directory' ),
$input->getOption( 'project' )
);
$generator->setTools( $input->getOption( 'suggestion-tools' ) );
$response = $generator->execute();
if ( $input->getOption( 'format' ) === 'json' ) {
$output->write( json_encode( $response ) );
}
return Command::SUCCESS;
}
return Command::SUCCESS;
......@@ -177,27 +149,11 @@ TAG
}
private function supportedCodeReview(): array {
return [ 'gerrit' ];
return [ Gerrit::ID ];
}
private function defaultCodeReview(): array {
return [ 'gerrit' ];
return [ Gerrit::ID ];
}
/**
* @param string $filename
*/
private function makeDirectoriesIfNeeded( string $filename ): void {
if ( !file_exists( dirname( $filename ) ) ) {
mkdir( dirname( $filename ), 0777, true );
}
}
/**
* @param InputInterface $input
* @return bool
*/
private function shouldRunPhpcs( InputInterface $input ): bool {
return in_array( 'phpcs', $input->getOption( 'suggestion-tools' ) );
}
}
......@@ -2,13 +2,12 @@
namespace FixSuggestions\Command;
use FixSuggestions\Http\Gerrit;
use FixSuggestions\Submitter\Gerrit;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\StreamableInputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class PostFixSuggestions extends Command {
......@@ -79,33 +78,23 @@ TAG
$output->writeln( "$suggestionsFile does not exist." );
return Command::FAILURE;
}
// TODO: Extract this into a class, when we add GitLab support.
if ( $codeReview === 'gerrit' ) {
$gerrit = new Gerrit(
if ( $codeReview === Gerrit::ID ) {
$gerritSubmitter = new Gerrit(
$input->getOption( 'gerrit-url' ),
$input->getOption( 'gerrit-username' ),
$input->getOption( 'gerrit-http-password' )
$input->getOption( 'gerrit-http-password' ),
$input->getOption( 'zuul-project' ),
$input->getOption( 'zuul-change' ),
$input->getOption( 'zuul-patchset' )
);
$suggestions = json_decode( file_get_contents( $suggestionsFile ), true );
try {
$response = $gerrit->postFixSuggestions(
$suggestions,
$input->getOption( 'zuul-project' ),
$input->getOption( 'zuul-change' ),
$input->getOption( 'zuul-patchset' )
);
if ( $response->getStatusCode() >= 400 ) {
$output->write( "\n<error>Error:</error> " );
$output->write( $response->getContent( false ), true );
return Command::FAILURE;
} else {
$output->write( '<info>done!</info>', true );
}
} catch ( TransportExceptionInterface $transportException ) {
$output->writeln( $transportException->getMessage() );
$response = $gerritSubmitter->execute( $suggestions );
if ( $response->getStatusCode() >= 400 ) {
$output->writeln( "\n<error>Error:</error> " );
$output->writeln( $response->getContent( false ), true );
return Command::FAILURE;
}
$output->writeln( '<info>done!</info>', true );
}
}
......
<?php
namespace FixSuggestions\Generator;
use Symfony\Component\Process\Process;
class Gerrit {
public const ID = 'gerrit';
/** @var string[] */
private $tools;
/** @var string */
private $cacheFile;
/** @var array */
private $files;
/** @var string */
private $workingDirectory;
/** @var string */
private $gerritRobotId;
/** @var string */
private $gerritRobotRunId;
/** @var string */
private $gerritRobotUrl;
/** @var string */
private $outputDirectory;
/** @var string */
private $project;
/**
* @param string $cacheFile
* @param string[] $files
* @param string $workingDirectory
* @param string $gerritRobotId
* @param string $gerritRobotRunId
* @param string $gerritRobotUrl
* @param string $outputDirectory
* @param string $project
*/
public function __construct(
string $cacheFile,
array $files,
string $workingDirectory,
string $gerritRobotId,
string $gerritRobotRunId,
string $gerritRobotUrl,
string $outputDirectory,
string $project
) {
$this->cacheFile = $cacheFile;
$this->files = $files;
$this->workingDirectory = $workingDirectory;
$this->gerritRobotId = $gerritRobotId;
$this->gerritRobotRunId = $gerritRobotRunId;
$this->gerritRobotUrl = $gerritRobotUrl;
$this->outputDirectory = $outputDirectory;
$this->project = $project;
}
/**
* @param array $tools
*/
public function setTools( array $tools ) {
$this->tools = $tools;
}
public function execute(): array {
$this->makeDirectoriesIfNeeded( $this->cacheFile );
$response = [];
if ( $this->shouldRunPhpcs() ) {
$phpcsCommand = [
'vendor/bin/phpcs',
'--cache=' . $this->cacheFile,
'-q',
'--report=vendor/mediawiki/mediawiki-codesniffer/MediaWiki/Reports/GerritRobotComments.php'
];
$process = new Process(
array_merge( $phpcsCommand, $this->files ),
$this->workingDirectory,
[
'GERRIT_ROBOT_ID' => $this->gerritRobotId,
'GERRIT_ROBOT_RUN_ID' => $this->gerritRobotRunId,
'GERRIT_URL' => $this->gerritRobotUrl,
'PHPCS_ROOT_DIR' => $this->workingDirectory
]
);
$process->run();
// No lint errors, return early.
if ( $process->getExitCode() === 0 ) {
return $response;
}
if ( $process->getExitCode() !== 2 ) {
// phpcs returns exit code 2 even when generating report properly.
throw new \Exception( $process->getErrorOutput() . "\n" . $process->getOutput() );
}
$outputFile = sprintf( '%s/%s/%s/phpcs.%s.json',
$this->outputDirectory,
self::ID,
$this->project,
$this->gerritRobotRunId
);
$this->makeDirectoriesIfNeeded( $outputFile );
file_put_contents(
$outputFile,
$process->getOutput()
);
$response['code_review'] = self::ID;
$response['suggestions']['phpcs'] = $outputFile;
}
return $response;
}
/**
* @param string $filename
*/
private function makeDirectoriesIfNeeded( string $filename ): void {
if ( !file_exists( dirname( $filename ) ) ) {
mkdir( dirname( $filename ), 0777, true );
}
}
private function shouldRunPhpcs(): bool {
return in_array( 'phpcs', $this->tools );
}
}
......@@ -2,7 +2,6 @@
namespace FixSuggestions\Http;
use http\Client\Response;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
......@@ -10,7 +9,8 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
class Gerrit {
private HttpClientInterface $client;
/** @var HttpClientInterface */
private $client;
/**
* @param string $url
......
<?php
namespace FixSuggestions\Submitter;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
class Gerrit {
public const ID = 'gerrit';
/**
* @var string
*/
private $zuulProject;
/**
* @var int
*/
private $zuulChange;
/**
* @var int
*/
private $zuulPatchset;
/**
* @var \FixSuggestions\Http\Gerrit
*/
private $gerritHttpClient;
/**
* @param string $gerritUrl
* @param string $gerritUsername
* @param string $gerritPassword
* @param string $zuulProject
* @param int $zuulChange
* @param int $zuulPatchset
*/
public function __construct(
string $gerritUrl,
string $gerritUsername,
string $gerritPassword,
string $zuulProject,
int $zuulChange,
int $zuulPatchset
) {
$this->gerritHttpClient = new \FixSuggestions\Http\Gerrit(
$gerritUrl,
$gerritUsername,
$gerritPassword
);
$this->zuulProject = $zuulProject;
$this->zuulChange = $zuulChange;
$this->zuulPatchset = $zuulPatchset;
}
/**
* @param array $suggestions
* @return ResponseInterface
* @throws TransportExceptionInterface
*/
public function execute( array $suggestions ): ResponseInterface {
return $this->gerritHttpClient->postFixSuggestions(
$suggestions,
$this->zuulProject,
$this->zuulChange,
$this->zuulPatchset
);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment