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.5.0] - 2025-01-29
### Added
- Optional option `--strict` for `list-unowned-files` to make the command usable in CI ([#23](https://github.com/timoschinkel/codeowners-cli/pull/23))

## [1.4.1] - 2025-01-29
### Removed
- Dropped support for PHP 8.0
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Arguments:

Options:
-c, --codeowners=CODEOWNERS Location of code owners file, defaults to <working_dir>/CODEOWNERS
--strict Return a non-zero exit code when there are unowned files
```

For example:
Expand Down
13 changes: 12 additions & 1 deletion src/Command/ListUnownedFilesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;

Expand Down Expand Up @@ -54,6 +55,12 @@ public function configure(): void
'c',
InputArgument::OPTIONAL,
'Location of code owners file, defaults to <working_dir>/CODEOWNERS'
)
->addOption(
'strict',
null,
InputOption::VALUE_NONE,
'Return a non-zero exit code when there are unowned files'
);
}

Expand Down Expand Up @@ -83,6 +90,7 @@ public function execute(InputInterface $input, OutputInterface $output): int

$finder = new Finder();

$unownedFilesFound = false;
foreach ($finder->in($paths)->files() as $file) {
/** @var SplFileInfo $file */
try {
Expand All @@ -93,11 +101,14 @@ public function execute(InputInterface $input, OutputInterface $output): int

$matcher->match($filePath);
} catch (NoMatchFoundException $exception) {
$unownedFilesFound = true;
$output->writeln((string)$file);
}
}

return 0;
return $input->getOption('strict') && $unownedFilesFound
? 1
: 0;
}

private function normalizePaths(array $paths): array
Expand Down
61 changes: 57 additions & 4 deletions tests/Command/ListUnownedFilesCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,65 @@ public function testCommandListFilesOwnedBySpecifiedOwner(): void
$this->patternMatcherFactory->reveal()
);

$output = $this->executeCommand($command, [
['exit' => $exit, 'output' => $output] = $this->executeCommand($command, [
'paths' => [
$filesystem->url() . '/folder',
]
]);

self::assertEquals(0, $exit);
self::assertEquals(
$filesystem->url() . '/folder/not-owned-by-owner' . PHP_EOL,
$output
);
}

public function testCommandListFilesOwnedBySpecifiedOwnerInStrictMode(): void
{
$filesystem = vfsStream::setup('root', 444, [
'CODEOWNERS' => '#',
'folder' => [
'owned-by-owner' => '#',
'not-owned-by-owner' => '#',
],
]);

$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('folder/owned-by-owner')
->willReturn(new Pattern('*', ['@owner']));

$this->patternMatcher
->match('folder/not-owned-by-owner')
->willThrow(NoMatchFoundException::class);

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

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

['exit' => $exit, 'output' => $output] = $this->executeCommand($command, [
'paths' => [
$filesystem->url() . '/folder',
],
'--strict' => true
]);

self::assertNotEquals(0, $exit);
self::assertEquals(
$filesystem->url() . '/folder/not-owned-by-owner' . PHP_EOL,
$output
Expand Down Expand Up @@ -146,14 +199,14 @@ public function testCommandPassesSpecifiedCodeownersFileToFileLocator(): void
]);
}

private function executeCommand(Command $command, array $parameters): string
private function executeCommand(Command $command, array $parameters): array
{
$application = new Application();
$application->add($command);

$tester = new CommandTester($application->find($command->getName()));
$tester->execute($parameters);
$exit = $tester->execute($parameters);

return $tester->getDisplay();
return ['exit' => $exit, 'output' => $tester->getDisplay()];
}
}