Skip to content

Commit 562fade

Browse files
committed
Adds the --preset option to the validate command
1 parent 0c60f0a commit 562fade

File tree

7 files changed

+119
-15
lines changed

7 files changed

+119
-15
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
77

88
## [Unreleased]
99

10+
## [v4.7.0] - 2025-08-29
11+
12+
### Added
13+
- New `preset` option for the validate command. Closes [#53](https://github.com/raphaelstolt/lean-package-validator/issues/53).
14+
1015
## [v4.6.0] - 2025-08-27
1116

1217
### Added

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ The `--enforce-alignment` option will enforce a strict alignment of export-ignor
147147
in the `.gitattributes` file and fail validation if they aren't aligned. Per __default__
148148
no alignment is enforced.
149149

150+
The `--preset=[<preset>]` option will use a predefined set of glob pattern.
151+
Available presets are `PHP`, `Python`, `Rust`, `JavaScript`, and `Go`. With `PHP` being the default.
152+
150153
The `--validate-git-archive` option will validate that no common repository artifacts slip
151154
into the release/dist archive file. It will do so by creating a `temporary archive` from the
152155
current Git `HEAD` and inspecting its content. With a set `--keep-license` option a license

phpstan.neon.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ parameters:
1919
- '#TMock#'
2020
- '#unknown class#'
2121
- '#set_error_handler expects#'
22+
- '#getPresetByLanguageName#'

src/Analyser.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
namespace Stolt\LeanPackage;
44

5-
use PHPStan\Type\Php\DateIntervalDynamicReturnTypeExtension;
65
use Stolt\LeanPackage\Exceptions\InvalidGlobPattern;
76
use Stolt\LeanPackage\Exceptions\InvalidGlobPatternFile;
87
use Stolt\LeanPackage\Exceptions\NonExistentGlobPatternFile;
8+
use Stolt\LeanPackage\Exceptions\PresetNotAvailable;
99
use Stolt\LeanPackage\Presets\Finder;
1010

1111
class Analyser
@@ -47,7 +47,7 @@ class Analyser
4747
private string $globPattern;
4848

4949
/**
50-
* The preferred end of line sequence
50+
* The preferred end-of-line sequence
5151
*
5252
* @var string
5353
*/
@@ -128,7 +128,7 @@ class Analyser
128128
private string $keepGlobPattern = '';
129129

130130
/**
131-
* Whether to align the export-ignores on create or overwrite
131+
* Whether to align the export-ignores on creation or overwrite
132132
* or not.
133133
*
134134
* @var boolean
@@ -961,8 +961,9 @@ public function hasCompleteExportIgnores(): bool
961961

962962
$actualExportIgnores = $this->getPresentExportIgnores();
963963

964+
$staleExportIgnores = [];
965+
964966
if ($this->isStaleExportIgnoresComparisonEnabled()) {
965-
$staleExportIgnores = [];
966967
$unfilteredExportIgnores = $this->getPresentExportIgnores(false);
967968
foreach ($unfilteredExportIgnores as $unfilteredExportIgnore) {
968969
if (false === \file_exists($unfilteredExportIgnore)) {
@@ -983,4 +984,12 @@ public function hasCompleteExportIgnores(): bool
983984

984985
return \array_values($expectedExportIgnores) === \array_values($actualExportIgnores);
985986
}
987+
988+
/**
989+
* @throws PresetNotAvailable
990+
*/
991+
public function setGlobPatternFromPreset(string $preset): void
992+
{
993+
$this->globPattern = '{' . \implode(',', $this->finder->getPresetGlobByLanguageName($preset)) . '}*';
994+
}
986995
}

src/Commands/ValidateCommand.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Stolt\LeanPackage\Exceptions\InvalidGlobPatternFile;
1818
use Stolt\LeanPackage\Exceptions\NoLicenseFilePresent;
1919
use Stolt\LeanPackage\Exceptions\NonExistentGlobPatternFile;
20+
use Stolt\LeanPackage\Exceptions\PresetNotAvailable;
2021
use Stolt\LeanPackage\Helpers\InputReader;
2122
use Symfony\Component\Console\Command\Command;
2223
use Symfony\Component\Console\Input\InputArgument;
@@ -33,6 +34,8 @@ final class ValidateCommand extends Command
3334
*/
3435
protected string $defaultLpvFile = WORKING_DIRECTORY . DIRECTORY_SEPARATOR . '.lpv';
3536

37+
protected string $defaultPreset = 'Php';
38+
3639
/**
3740
* Package analyser.
3841
*
@@ -108,6 +111,7 @@ protected function configure(): void
108111
. 'export-ignored';
109112
$globPatternFileDescription = 'Use this file with glob patterns '
110113
. 'to match artifacts which should be export-ignored';
114+
$presetDescription = 'Use the glob pattern of the given language preset';
111115

112116
$keepLicenseDescription = 'Do not export-ignore the license file';
113117
$keepReadmeDescription = 'Do not export-ignore the README file';
@@ -152,6 +156,13 @@ protected function configure(): void
152156
$globPatternFileDescription,
153157
$this->defaultLpvFile
154158
);
159+
$this->addOption(
160+
'preset',
161+
null,
162+
InputOption::VALUE_OPTIONAL,
163+
$presetDescription,
164+
$this->defaultPreset
165+
);
155166
$this->addOption(
156167
'keep-license',
157168
null,
@@ -216,6 +227,7 @@ protected function configure(): void
216227
protected function execute(InputInterface $input, OutputInterface $output): int
217228
{
218229
$directory = (string) $input->getArgument('directory');
230+
$chosenPreset = (string) $input->getOption('preset');
219231

220232
if ($directory !== WORKING_DIRECTORY) {
221233
try {
@@ -380,6 +392,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
380392

381393
$this->analyser->setGlobPatternFromFile($globPatternFile);
382394
}
395+
383396
} catch (NonExistentGlobPatternFile $e) {
384397
$warning = "Warning: The provided glob pattern file "
385398
. "'$globPatternFile' doesn't exist.";
@@ -397,6 +410,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int
397410

398411
$output->writeln($e->getMessage(), OutputInterface::VERBOSITY_DEBUG);
399412

413+
return Command::FAILURE;
414+
}
415+
} elseif ($chosenPreset) {
416+
try {
417+
418+
$verboseOutput = '+ Using the ' . $chosenPreset . ' language preset.';
419+
$output->writeln($verboseOutput, OutputInterface::VERBOSITY_VERBOSE);
420+
421+
$this->analyser->setGlobPatternFromPreset($chosenPreset);
422+
} catch (PresetNotAvailable $e) {
423+
$warning = 'Warning: The chosen language preset ' . $chosenPreset . ' is not available. Maybe contribute it?.';
424+
$outputContent = '<error>' . $warning . '</error>';
425+
$output->writeln($outputContent);
426+
400427
return Command::FAILURE;
401428
}
402429
}
@@ -456,7 +483,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
456483
. 'content.</info>';
457484
$output->writeln($outputContent);
458485

459-
return 1;
486+
return Command::FAILURE;
460487
} elseif ($validateArchive) {
461488
try {
462489
$verboseOutput = '+ Validating Git archive.';

src/Presets/Finder.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ public function getAvailablePresets(): array
4747
* @return array
4848
*/
4949
public function getPresetGlobByLanguageName(string $name): array
50+
{
51+
$preset = $this->getPresetByLanguageName($name);
52+
53+
return $preset->getPresetGlob();
54+
}
55+
56+
/**
57+
* @param string $name
58+
* @throws PresetNotAvailable
59+
* @return Preset
60+
*/
61+
public function getPresetByLanguageName(string $name): Preset
5062
{
5163
$name = \ucfirst(\strtolower($name));
5264

@@ -57,10 +69,7 @@ public function getPresetGlobByLanguageName(string $name): array
5769

5870
$presetClassName = \sprintf('Stolt\LeanPackage\Presets\%sPreset', $name);
5971

60-
/** @var Preset $preset **/
61-
$preset = new $presetClassName();
62-
63-
return $preset->getPresetGlob();
72+
return new $presetClassName();
6473
}
6574

6675
/**

tests/Commands/ValidateCommandTest.php

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Stolt\LeanPackage\Archive;
1818
use Stolt\LeanPackage\Archive\Validator;
1919
use Stolt\LeanPackage\Commands\ValidateCommand;
20+
use Stolt\LeanPackage\Exceptions\InvalidGlobPattern;
2021
use Stolt\LeanPackage\Exceptions\NoLicenseFilePresent;
2122
use Stolt\LeanPackage\Helpers\Str as OsHelper;
2223
use Stolt\LeanPackage\Presets\Finder;
@@ -34,7 +35,7 @@ class ValidateCommandTest extends TestCase
3435
use InteractsWithConsole;
3536

3637
/**
37-
* Set up test environment.
38+
* Set up a test environment.
3839
*/
3940
protected function setUp(): void
4041
{
@@ -53,7 +54,7 @@ protected function setUp(): void
5354
}
5455

5556
/**
56-
* Tear down test environment.
57+
* Tear down the test environment.
5758
*
5859
* @return void
5960
*/
@@ -195,9 +196,10 @@ public function showsDifferenceBetweenActualAndExpectedGitattributesContent(): v
195196
#[Test]
196197
public function filesInGlobalGitignoreAreExportIgnored(): void
197198
{
198-
$analyserMock = Mockery::mock(Analyser::class)->makePartial();
199-
200199
$globPattern = '{' . \implode(',', (new PhpPreset())->getPresetGlob()) . '}*';
200+
201+
$analyserMock = Mockery::mock(Analyser::class, [new Finder(new PhpPreset())])->makePartial();
202+
201203
$analyserMock->setGlobPattern($globPattern);
202204

203205
$application = $this->getApplicationWithMockedAnalyser($analyserMock);
@@ -265,7 +267,7 @@ public function filesInGlobalGitignoreAreExportIgnored(): void
265267
#[Ticket('https://github.com/raphaelstolt/lean-package-validator/issues/16')]
266268
public function gitattributesFileWithNoExportIgnoresContentShowsExpectedContent(): void
267269
{
268-
$analyserMock = Mockery::mock(Analyser::class)->makePartial();
270+
$analyserMock = Mockery::mock(Analyser::class, [new Finder(new PhpPreset())])->makePartial();
269271

270272
$globPattern = '{' . \implode(',', (new PhpPreset())->getPresetGlob()) . '}*';
271273
$analyserMock->setGlobPattern($globPattern);
@@ -1302,10 +1304,13 @@ public function nonLeanArchiveIsNotConsideredLeanSingular(): void
13021304
$this->assertTrue($commandTester->getStatusCode() > Command::SUCCESS);
13031305
}
13041306

1307+
/**
1308+
* @throws InvalidGlobPattern
1309+
*/
13051310
#[Test]
13061311
public function impossibilityToResolveExpectedGitattributesFileContentIsInfoed(): void
13071312
{
1308-
$mock = Mockery::mock(Analyser::class)->makePartial();
1313+
$mock = Mockery::mock(Analyser::class, [new Finder(new PhpPreset())])->makePartial();
13091314

13101315
$globPattern = '{' . \implode(',', (new PhpPreset())->getPresetGlob()) . '}*';
13111316
$mock->setGlobPattern($globPattern);
@@ -2283,6 +2288,51 @@ public function detectsValidGitattributeContentInStdinInput(): void
22832288
->assertSuccessful();
22842289
}
22852290

2291+
#[Test]
2292+
#[RunInSeparateProcess]
2293+
public function usesTheRustPresetIfRequested(): void
2294+
{
2295+
$artifactFilenames = [
2296+
'CODE_OF_CONDUCT.md',
2297+
'.rustfmt.toml',
2298+
'.clippy.toml',
2299+
'LICENSE.md',
2300+
];
2301+
2302+
$this->createTemporaryFiles(
2303+
$artifactFilenames,
2304+
['src']
2305+
);
2306+
2307+
$gitattributesContent = <<<CONTENT
2308+
* text=auto eol=lf
2309+
2310+
.clippy.toml export-ignore
2311+
.gitattributes export-ignore
2312+
.rustfmt.toml export-ignore
2313+
CODE_OF_CONDUCT.md export-ignore
2314+
LICENSE.md export-ignore
2315+
CONTENT;
2316+
2317+
$expectedDisplay = <<<CONTENT
2318+
The present .gitattributes file is considered valid.
2319+
2320+
CONTENT;
2321+
2322+
$this->createTemporaryGitattributesFile($gitattributesContent);
2323+
2324+
$command = $this->application->find('validate');
2325+
$commandTester = new CommandTester($command);
2326+
$commandTester->execute([
2327+
'command' => $command->getName(),
2328+
'directory' => WORKING_DIRECTORY,
2329+
'--preset' => 'Rust',
2330+
]);
2331+
2332+
$this->assertSame($expectedDisplay, $commandTester->getDisplay());
2333+
$commandTester->assertCommandIsSuccessful();
2334+
}
2335+
22862336
/**
22872337
* @return array
22882338
*/

0 commit comments

Comments
 (0)