🚧 This instance is under construction; expect occasional downtime. Runners available in /repos. Questions? Ask in #wikimedia-gitlab on libera.chat, or under GitLab on Phabricator.

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