Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.6.0] - 2025-05-28
### Added
- `-o`/`--owner-only` option for `codeowners owner` to print only the owner ([#26](https://github.com/timoschinkel/codeowners-cli/pull/26))

## [1.5.1] - 2025-01-30
### Added
- Support for Symfony 7 (next to Symfony 6) ([#24](https://github.com/timoschinkel/codeowners-cli/pull/24))
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Arguments:

Options:
-c, --codeowners=CODEOWNERS Location of code owners file, defaults to <working_dir>/CODEOWNERS
-o, --owner-only Suppress normal output, only output the owner when applicable
```

For example:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^6.0",
"vimeo/psalm": "~6.4.0",
"phpunit/phpunit": "^9.4",
"mikey179/vfsstream": "^1.6",
"phpspec/prophecy-phpunit": "^2.0"
Expand Down
31 changes: 21 additions & 10 deletions src/Command/OwnerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@
use CodeOwners\Cli\FileLocator\FileLocatorFactoryInterface;
use CodeOwners\Cli\PatternMatcherFactoryInterface;
use CodeOwners\Exception\NoMatchFoundException;
use CodeOwners\Parser;
use CodeOwners\Pattern;
use CodeOwners\PatternMatcher;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

final class OwnerCommand extends Command
Expand Down Expand Up @@ -58,6 +55,12 @@ public function configure(): void
InputArgument::OPTIONAL,
'Location of code owners file, defaults to <working_dir>/CODEOWNERS'
)
->addOption(
'owner-only',
'o',
InputOption::VALUE_NONE,
'Suppress normal output, only output the owner when applicable'
)
;
}

Expand All @@ -84,19 +87,27 @@ protected function execute(InputInterface $input, OutputInterface $output): int

foreach ($paths as $path) {
if (file_exists($this->workingDirectory . '/' . $path) === false) {
$output->writeln("🚫 \"{$path}\" does not exist");
if ($input->getOption('owner-only') !== true) {
$output->writeln("🚫 \"{$path}\" does not exist");
}
continue;
}

try {
$pattern = $matcher->match($path);

$owners = $this->formatOwners($pattern);
$output->writeln(
"✅ \"{$path}\" is owned by {$owners} according to pattern \"{$pattern->getPattern()}\""
);
if ($input->getOption('owner-only') === true) {
$output->writeln(join(PHP_EOL, $pattern->getOwners()));
} else {
$owners = $this->formatOwners($pattern);
$output->writeln(
"✅ \"{$path}\" is owned by {$owners} according to pattern \"{$pattern->getPattern()}\""
);
}
} catch (NoMatchFoundException $exception) {
$output->writeln("🚫 \"{$path}\" has no code owner");
if ($input->getOption('owner-only') !== true) {
$output->writeln("🚫 \"{$path}\" has no code owner");
}
}
}

Expand Down
46 changes: 46 additions & 0 deletions tests/Command/OwnerCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,52 @@ public function testCommandDisplaysOwnersFoundForPaths(): void
self::assertMatchesRegularExpression('/"file-non-existent".+does not exist/m', $output);
}

public function testCommandDisplaysOwnersOnlyFoundForPaths(): void
{
$filesystem = vfsStream::setup('root', 444, [
'CODEOWNERS' => '#',
'file-a' => '#',
'file-b' => '#',
]);

$fileLocator = $this->prophesize(FileLocatorInterface::class);
$fileLocator->locateFile()
->shouldBeCalled()
->willReturn($filesystem->url() . '/CODEOWNERS');

$this->fileLocatorFactory
->getFileLocator(Argument::type('string'), null)
->shouldBeCalled()
->willReturn($fileLocator->reveal());

$this->patternMatcher
->match('file-a')
->shouldBeCalled()
->willReturn(new Pattern('file-a', ['@owner-a', '@owner-b']));
$this->patternMatcher
->match('file-b')
->shouldBeCalled()
->willThrow(NoMatchFoundException::class);

$this->patternMatcherFactory
->getPatternMatcher($filesystem->url() . '/CODEOWNERS')
->shouldBeCalled()
->willReturn($this->patternMatcher->reveal());

$command = new OwnerCommand(
$filesystem->url(),
$this->fileLocatorFactory->reveal(),
$this->patternMatcherFactory->reveal()
);

$output = $this->executeCommand(
$command,
['paths' => ['file-a', 'file-b', 'file-non-existent'], '--owner-only' => true]
);

self::assertEquals('@owner-a' . PHP_EOL . '@owner-b' . PHP_EOL, $output);
}

public function testCommandPassesCodeownerFileLocation(): void
{
$filesystem = vfsStream::setup('root', 444, []);
Expand Down