Skip to content

Commit

Permalink
Auto-complete fork names for "sync" and "bc" commands
Browse files Browse the repository at this point in the history
  • Loading branch information
aik099 committed Dec 12, 2024
1 parent 5d2ea6e commit f862f5b
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 28 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Added
...
- The fork names are auto-completed for `sync` (`--project-fork` option) and `bc` (`--source-project-fork` and `--target-project-fork` options) commands.

### Changed
...
Expand Down
24 changes: 20 additions & 4 deletions src/CodeInsight/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@


use ConsoleHelpers\ConsoleKit\Command\AbstractCommand as BaseCommand;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;

/**
* Base command class.
Expand All @@ -29,18 +32,31 @@ protected function prepareDependencies()
$container = $this->getContainer();
}

/**
* Returns input from completion context.
*
* @param CompletionContext $context Completion context.
*
* @return InputInterface
*/
protected function getInputFromCompletionContext(CompletionContext $context)
{
$words = $context->getWords();
array_splice($words, 1, 1); // Remove the command name.

return new ArgvInput($words, $this->getDefinition());
}

/**
* Returns and validates path.
*
* @param string $argument_name Argument name, that contains path.
* @param string $raw_path Raw path.
*
* @return string
* @throws \InvalidArgumentException When path isn't valid.
*/
protected function getPath($argument_name)
protected function getPath($raw_path)
{
$raw_path = $this->io->getArgument($argument_name);

if ( !$raw_path ) {
return '';
}
Expand Down
72 changes: 54 additions & 18 deletions src/CodeInsight/Command/BackwardsCompatibilityCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use ConsoleHelpers\CodeInsight\KnowledgeBase\KnowledgeBaseFactory;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -124,6 +125,18 @@ public function completeOptionValues($optionName, CompletionContext $context)
{
$ret = parent::completeOptionValues($optionName, $context);

if ( $optionName === 'source-project-fork' ) {
$input = $this->getInputFromCompletionContext($context);

return $this->_knowledgeBaseFactory->getForks($this->getSourcePath($input, true));
}

if ( $optionName === 'target-project-fork' ) {
$input = $this->getInputFromCompletionContext($context);

return $this->_knowledgeBaseFactory->getForks($this->getTargetPath($input));
}

if ( $optionName === 'format' ) {
return $this->_reporterFactory->getNames();
}
Expand All @@ -133,33 +146,18 @@ public function completeOptionValues($optionName, CompletionContext $context)

/**
* {@inheritdoc}
*
* @throws RuntimeException When source project path is missing.
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// Get reporter upfront so that we can error out early for invalid reporters.
$reporter = $this->_reporterFactory->get($this->io->getOption('format'));

$source_path = $this->getPath('source-project-path');
$target_path = $this->getPath('target-project-path');

$source_fork = $this->io->getOption('source-project-fork');

if ( !$source_path ) {
if ( $source_fork ) {
// Single code base, but comparing with fork.
$source_path = $target_path;
}
else {
// Not using fork, then need to specify project path.
throw new RuntimeException('Not enough arguments (missing: "source-project-path").');
}
}
$source_path = $this->getSourcePath($input, false);
$target_path = $this->getTargetPath($input);

$source_knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
$source_path,
$source_fork,
$this->io->getOption('source-project-fork'),
$this->io
);
$target_knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
Expand All @@ -181,6 +179,44 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->io->writeln($reporter->generate($bc_breaks));
}

/**
* Returns source path.
*
* @param InputInterface $input Input.
* @param boolean $autocomplete Autocomplete.
*
* @return string
* @throws RuntimeException When source project path is missing.
*/
protected function getSourcePath(InputInterface $input, $autocomplete)
{
$source_path = $this->getPath($input->getArgument('source-project-path'));

if ( $source_path ) {
return $source_path;
}

// Single code base, but comparing with fork OR autocompleting forks.
if ( $autocomplete || $input->getOption('source-project-fork') ) {
return $this->getTargetPath($input);
}

// Not using fork, then need to specify project path.
throw new RuntimeException('Not enough arguments (missing: "source-project-path").');
}

/**
* Returns target path.
*
* @param InputInterface $input Input.
*
* @return string
*/
protected function getTargetPath(InputInterface $input)
{
return $this->getPath($input->getArgument('target-project-path'));
}

/**
* Finds backward compatibility breaks.
*
Expand Down
4 changes: 2 additions & 2 deletions src/CodeInsight/Command/MissingTestsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$src_path = $this->getPath('src-path');
$tests_path = $this->getPath('tests-path');
$src_path = $this->getPath($this->io->getArgument('src-path'));
$tests_path = $this->getPath($this->io->getArgument('tests-path'));

$finder = new Finder();
$finder->files()->name('*.php')->notName('/^(I[A-Z]|Abstract[A-Z])/')->in($src_path);
Expand Down
2 changes: 1 addition & 1 deletion src/CodeInsight/Command/ReportCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protected function prepareDependencies()
protected function execute(InputInterface $input, OutputInterface $output)
{
$knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
$this->getPath('project-path'),
$this->getPath($this->io->getArgument('project-path')),
$this->io->getOption('project-fork'),
$this->io
);
Expand Down
26 changes: 25 additions & 1 deletion src/CodeInsight/Command/SyncCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


use ConsoleHelpers\CodeInsight\KnowledgeBase\KnowledgeBaseFactory;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -63,13 +64,36 @@ protected function prepareDependencies()
$this->_knowledgeBaseFactory = $container['knowledge_base_factory'];
}

/**
* Return possible values for the named option
*
* @param string $optionName Option name.
* @param CompletionContext $context Completion context.
*
* @return array
*/
public function completeOptionValues($optionName, CompletionContext $context)
{
$ret = parent::completeOptionValues($optionName, $context);

if ( $optionName === 'project-fork' ) {
$input = $this->getInputFromCompletionContext($context);

return $this->_knowledgeBaseFactory->getForks(
$this->getPath($input->getArgument('project-path'))
);
}

return $ret;
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
$this->getPath('project-path'),
$this->getPath($this->io->getArgument('project-path')),
$this->io->getOption('project-fork'),
$this->io
);
Expand Down
36 changes: 35 additions & 1 deletion src/CodeInsight/KnowledgeBase/DatabaseManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function __construct(MigrationManager $migration_manager, $working_direct
*/
public function getDatabase($project_path, $fork = null)
{
if ( substr($project_path, 0, 1) !== '/' ) {
if ( strpos($project_path, '/') !== 0 ) {
throw new \InvalidArgumentException('The "$project_path" argument must contain absolute path.');
}

Expand All @@ -85,6 +85,40 @@ public function getDatabase($project_path, $fork = null)
return new ExtendedPdo('sqlite:' . $fork_db_file);
}

/**
* Returns forks for given project.
*
* @param string $project_path Project path.
*
* @return string[]
* @throws \InvalidArgumentException When relative project path is given.
*/
public function getForks($project_path)
{
if ( strpos($project_path, '/') !== 0 ) {
throw new \InvalidArgumentException('The "$project_path" argument must contain absolute path.');
}

$project_path = $this->_databaseDirectory . $project_path;

if ( !file_exists($project_path) ) {
return array();
}

$ret = array();
$absolute_forks = glob($project_path . '/code_insight-*.sqlite');

foreach ( $absolute_forks as $absolute_fork ) {
$ret[] = preg_replace(
'/^' . preg_quote($project_path . '/code_insight-', '/') . '(.+).sqlite/',
'$1',
$absolute_fork
);
}

return $ret;
}

/**
* Runs outstanding migrations on the database.
*
Expand Down
12 changes: 12 additions & 0 deletions src/CodeInsight/KnowledgeBase/KnowledgeBaseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,16 @@ public function getKnowledgeBase($project_path, $fork = null, ConsoleIO $io = nu
return $knowledge_base;
}

/**
* Returns forks for given project.
*
* @param string $project_path Project path.
*
* @return string[]
*/
public function getForks($project_path)
{
return $this->_databaseManager->getForks($project_path);
}

}
41 changes: 41 additions & 0 deletions tests/CodeInsight/KnowledgeBase/DatabaseManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,47 @@ public function testCreatingForkedDatabaseFromOriginal()
);
}

public function testRelativeProjectPathForksError()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The "$project_path" argument must contain absolute path.');

$this->getDatabaseManager()->getForks('relative/path');
}

/**
* @depends testCreatingDatabase
*/
public function testNoForksWithProjectDatabase()
{
$database_manager = $this->getDatabaseManager();
$database_manager->getDatabase('/absolute/path');

$this->assertEmpty($database_manager->getForks('/absolute/path'));
}

public function testNoForksWithoutProjectDatabase()
{
$database_manager = $this->getDatabaseManager();

$this->assertEmpty($database_manager->getForks('/absolute/path'));
}

public function testGetForks()
{
$database_manager = $this->getDatabaseManager();
$original_database = $database_manager->getDatabase('/absolute/path');
$original_database->perform('CREATE TABLE "SampleTableOrg" ("Name" TEXT(255,0) NOT NULL, PRIMARY KEY("Name"))');

$db_fork1 = $database_manager->getDatabase('/absolute/path', 'fork1');
$db_fork1->perform('CREATE TABLE "SampleTableFork1" ("Name" TEXT(255,0) NOT NULL, PRIMARY KEY("Name"))');

$db_fork2 = $database_manager->getDatabase('/absolute/path', 'fork2');
$db_fork2->perform('CREATE TABLE "SampleTableFork2" ("Name" TEXT(255,0) NOT NULL, PRIMARY KEY("Name"))');

$this->assertEquals(array('fork1', 'fork2'), $database_manager->getForks('/absolute/path'));
}

/**
* Returns database DSN.
*
Expand Down

0 comments on commit f862f5b

Please sign in to comment.