Skip to content

Commit 5cd8fc1

Browse files
committed
refactor(deps): remove composer/composer package dependency
The composer/composer package dependency was only used to read the contents of the extra section of a project's composer.json file. This commit replaces this logic by standard PHP functions. As a result, the composer/composer dependency has been removed which results in potentially 21 less dependencies when installing this package as a dependency. Closes: #103
1 parent 1911eb2 commit 5cd8fc1

File tree

3 files changed

+71
-130
lines changed

3 files changed

+71
-130
lines changed

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"php": "^8.1",
2525
"ext-json": "*",
2626
"composer-runtime-api": "^2.0",
27-
"composer/composer": "^2.4",
2827
"jawira/case-converter": "^3.5",
2928
"opis/json-schema": "^2.3",
3029
"symfony/console": "^6.0 || ^7.0",

src/ConventionalCommits/Configuration/FinderTool.php

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121

2222
namespace Ramsey\ConventionalCommits\Configuration;
2323

24-
use Composer\Composer;
25-
use Composer\Factory;
26-
use Composer\IO\ConsoleIO;
2724
use JsonException;
2825
use Opis\JsonSchema\Errors\ErrorFormatter;
2926
use Opis\JsonSchema\Errors\ValidationError;
@@ -32,7 +29,7 @@
3229
use Ramsey\ConventionalCommits\Exception\ComposerNotFound;
3330
use Ramsey\ConventionalCommits\Exception\InvalidArgument;
3431
use Ramsey\ConventionalCommits\Exception\InvalidValue;
35-
use Symfony\Component\Console\Helper\HelperSet;
32+
use RuntimeException;
3633
use Symfony\Component\Console\Input\InputInterface;
3734
use Symfony\Component\Console\Output\OutputInterface;
3835
use Symfony\Component\Filesystem\Filesystem;
@@ -43,6 +40,7 @@
4340
use function gettype;
4441
use function implode;
4542
use function is_array;
43+
use function is_readable;
4644
use function json_decode;
4745
use function realpath;
4846
use function sprintf;
@@ -84,23 +82,6 @@ public function findConfiguration(
8482
return new DefaultConfiguration($this->loadConfigFromComposer($input, $output));
8583
}
8684

87-
/**
88-
* Returns the Composer instance for the current project
89-
*/
90-
public function getComposer(
91-
InputInterface $input,
92-
OutputInterface $output,
93-
Filesystem $filesystem,
94-
): Composer {
95-
$composerJson = $this->findComposerJson($filesystem);
96-
97-
$composerIO = new ConsoleIO($input, $output, new HelperSet());
98-
$composerFactory = new Factory();
99-
100-
/** @var Composer */
101-
return $composerFactory->createComposer($composerIO, $composerJson, true, null, true);
102-
}
103-
10485
/**
10586
* @return array{typeCase?: string | null, types?: string[], scopeRequired?: bool, scopeCase?: string | null, scopes?: string[], descriptionCase?: string | null, descriptionEndMark?: string | null, bodyRequired?: bool, bodyWrapWidth?: int | null, requiredFooters?: string[]}
10687
*
@@ -137,10 +118,17 @@ private function loadConfigFromFile(string $file): array
137118
*/
138119
private function loadConfigFromComposer(InputInterface $input, OutputInterface $output): array
139120
{
140-
$composer = $this->getComposer($input, $output, new Filesystem());
141-
121+
$composerJsonPath = $this->findComposerJson(new Filesystem());
122+
if (!is_readable($composerJsonPath)) {
123+
throw new RuntimeException(sprintf('The file "%s" is not readable.', $composerJsonPath));
124+
}
125+
$contents = file_get_contents($composerJsonPath);
126+
if ($contents === false) {
127+
throw new RuntimeException(sprintf('Could not read file "%s"', $composerJsonPath));
128+
}
129+
$composerData = json_decode($contents, true, flags: JSON_THROW_ON_ERROR);
142130
/** @var array{"ramsey/conventional-commits"?: array{config?: scalar | array{typeCase?: string | null, types?: string[], scopeRequired?: bool, scopeCase?: string | null, scopes?: string[], descriptionCase?: string | null, descriptionEndMark?: string | null, bodyRequired?: bool, bodyWrapWidth?: int | null, requiredFooters?: string[]}, configFile?: scalar}} | null $extra */
143-
$extra = $composer->getPackage()->getExtra();
131+
$extra = is_array($composerData) ? ($composerData['extra'] ?? null) : null;
144132

145133
$config = $extra['ramsey/conventional-commits']['config'] ?? null;
146134
$configFile = $extra['ramsey/conventional-commits']['configFile'] ?? null;

tests/ConventionalCommits/Configuration/FinderToolTest.php

Lines changed: 59 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44

55
namespace Ramsey\Test\ConventionalCommits\Configuration;
66

7-
use Composer\Composer;
87
use JsonException;
98
use Mockery\MockInterface;
109
use Ramsey\ConventionalCommits\Configuration\Configuration;
1110
use Ramsey\ConventionalCommits\Configuration\FinderTool;
12-
use Ramsey\ConventionalCommits\Exception\ComposerNotFound;
1311
use Ramsey\ConventionalCommits\Exception\InvalidArgument;
1412
use Ramsey\ConventionalCommits\Exception\InvalidValue;
1513
use Ramsey\Test\SnapshotsTool;
@@ -19,8 +17,11 @@
1917
use Symfony\Component\Console\Output\OutputInterface;
2018
use Symfony\Component\Filesystem\Filesystem;
2119

20+
use function file_put_contents;
2221
use function json_encode;
2322
use function realpath;
23+
use function sys_get_temp_dir;
24+
use function unlink;
2425

2526
use const DIRECTORY_SEPARATOR;
2627

@@ -34,6 +35,8 @@ class FinderToolTest extends TestCase
3435

3536
private OutputInterface & MockInterface $output;
3637

38+
private Filesystem $fileSystem;
39+
3740
protected function setUp(): void
3841
{
3942
parent::setUp();
@@ -43,6 +46,7 @@ protected function setUp(): void
4346
$this->finderTool = new class () {
4447
use FinderTool;
4548
};
49+
$this->fileSystem = new Filesystem();
4650
}
4751

4852
/**
@@ -168,184 +172,134 @@ public function testFindConfigurationThrowsExceptionWhenConfigIsInvalid(): void
168172
]);
169173
}
170174

171-
public function testGetComposerFindsComposerJsonForCurrentProject(): void
172-
{
173-
$this->output->shouldReceive('isDebug');
174-
$this->output->allows()->getVerbosity()->andReturn(OutputInterface::VERBOSITY_QUIET);
175-
$this->output->allows()->isDebug()->andReturnFalse();
176-
177-
$filesystem = new Filesystem();
178-
179-
// @phpstan-ignore-next-line
180-
$composer = $this->finderTool->getComposer($this->input, $this->output, $filesystem);
181-
182-
$this->assertInstanceOf(Composer::class, $composer);
183-
$this->assertSame('ramsey/conventional-commits', $composer->getPackage()->getName());
184-
}
185-
186-
public function testGetComposerThrowsExceptionWhenAutoloaderDoesNotExist(): void
187-
{
188-
$this->output->allows()->getVerbosity()->andReturn(OutputInterface::VERBOSITY_QUIET);
189-
190-
/** @var Filesystem & MockInterface $filesystem */
191-
$filesystem = $this->mockery(Filesystem::class);
192-
$filesystem->shouldReceive('exists')->twice()->andReturnFalse();
193-
194-
$this->expectException(ComposerNotFound::class);
195-
$this->expectExceptionMessage(
196-
'Could not find the autoloader. Did you run composer install or composer update?',
197-
);
198-
199-
// @phpstan-ignore-next-line
200-
$this->finderTool->getComposer($this->input, $this->output, $filesystem);
201-
}
202-
203-
public function testGetComposerThrowsExceptionWhenComposerJsonDoesNotExist(): void
204-
{
205-
$this->output->allows()->getVerbosity()->andReturn(OutputInterface::VERBOSITY_QUIET);
206-
207-
/** @var Filesystem & MockInterface $filesystem */
208-
$filesystem = $this->mockery(Filesystem::class);
209-
$filesystem->shouldReceive('exists')->andReturn(false, true, false);
210-
211-
$this->expectException(ComposerNotFound::class);
212-
$this->expectExceptionMessage('Could not find composer.json.');
213-
214-
// @phpstan-ignore-next-line
215-
$this->finderTool->getComposer($this->input, $this->output, $filesystem);
216-
}
217-
218175
public function testFindConfigurationThrowsExceptionWhenComposerHasInvalidValue(): void
219176
{
220-
/** @var Composer & MockInterface $composer */
221-
$composer = $this->mockery(Composer::class, [
222-
'getPackage->getExtra' => [
177+
$composerJsonPath = $this->fileSystem->tempnam(sys_get_temp_dir(), 'cc_', '.json');
178+
file_put_contents($composerJsonPath, json_encode([
179+
'extra' => [
223180
'ramsey/conventional-commits' => [
224181
'config' => 'invalid value',
225182
],
226183
],
227-
]);
184+
]));
228185

229-
$finderTool = new class () {
186+
$finderTool = new class ($composerJsonPath) {
230187
use FinderTool;
231188

232-
public Composer $composer;
189+
public function __construct(private string $path)
190+
{
191+
}
233192

234-
public function getComposer(
235-
InputInterface $input,
236-
OutputInterface $output,
237-
Filesystem $filesystem,
238-
): Composer {
239-
return $this->composer;
193+
// Override to point to our temp composer.json
194+
public function findComposerJson(Filesystem $filesystem): string
195+
{
196+
return $this->path;
240197
}
241198
};
242199

243-
$finderTool->composer = $composer;
244-
245200
$this->expectException(InvalidValue::class);
246201
$this->expectExceptionMessage(
247202
'Expected a configuration array in composer.json extra.ramsey/conventional-commits.config; '
248203
. 'received string instead.',
249204
);
250205

251206
$finderTool->findConfiguration($this->input, $this->output);
207+
208+
@unlink($composerJsonPath);
252209
}
253210

254211
public function testFindConfigurationReturnsConfigurationUsingComposerConfig(): void
255212
{
256-
/** @var Composer & MockInterface $composer */
257-
$composer = $this->mockery(Composer::class, [
258-
'getPackage->getExtra' => [
213+
$composerJsonPath = $this->fileSystem->tempnam(sys_get_temp_dir(), 'cc_', '.json');
214+
file_put_contents($composerJsonPath, json_encode([
215+
'extra' => [
259216
'ramsey/conventional-commits' => [
260217
'configFile' => (string) realpath(__DIR__ . '/../../configs/config-03.json'),
261218
'config' => [
262219
'typeCase' => 'pascal',
263220
],
264221
],
265222
],
266-
]);
223+
]));
267224

268-
$finderTool = new class () {
225+
$finderTool = new class ($composerJsonPath) {
269226
use FinderTool;
270227

271-
public Composer $composer;
228+
public function __construct(private string $path)
229+
{
230+
}
272231

273-
public function getComposer(
274-
InputInterface $input,
275-
OutputInterface $output,
276-
Filesystem $filesystem,
277-
): Composer {
278-
return $this->composer;
232+
public function findComposerJson(Filesystem $filesystem): string
233+
{
234+
return $this->path;
279235
}
280236
};
281237

282-
$finderTool->composer = $composer;
283-
284238
/** @var Configuration $configuration */
285239
$configuration = $finderTool->findConfiguration($this->input, $this->output);
286240

287241
$this->assertMatchesSnapshot(json_encode($configuration), new WindowsSafeTextDriver());
242+
243+
@unlink($composerJsonPath);
288244
}
289245

290246
public function testFindConfigurationReturnsConfigurationUsingComposerConfigFile(): void
291247
{
292-
/** @var Composer & MockInterface $composer */
293-
$composer = $this->mockery(Composer::class, [
294-
'getPackage->getExtra' => [
248+
$composerJsonPath = $this->fileSystem->tempnam(sys_get_temp_dir(), 'cc_', '.json');
249+
file_put_contents($composerJsonPath, json_encode([
250+
'extra' => [
295251
'ramsey/conventional-commits' => [
296252
'configFile' => (string) realpath(__DIR__ . '/../../configs/config-03.json'),
297253
],
298254
],
299-
]);
255+
]));
300256

301-
$finderTool = new class () {
257+
$finderTool = new class ($composerJsonPath) {
302258
use FinderTool;
303259

304-
public Composer $composer;
260+
public function __construct(private string $path)
261+
{
262+
}
305263

306-
public function getComposer(
307-
InputInterface $input,
308-
OutputInterface $output,
309-
Filesystem $filesystem,
310-
): Composer {
311-
return $this->composer;
264+
public function findComposerJson(Filesystem $filesystem): string
265+
{
266+
return $this->path;
312267
}
313268
};
314269

315-
$finderTool->composer = $composer;
316-
317270
/** @var Configuration $configuration */
318271
$configuration = $finderTool->findConfiguration($this->input, $this->output);
319272

320273
$this->assertMatchesSnapshot(json_encode($configuration), new WindowsSafeTextDriver());
274+
275+
@unlink($composerJsonPath);
321276
}
322277

323278
public function testFindConfigurationReturnsDefaultConfigurationWhenComposerHasNone(): void
324279
{
325-
/** @var Composer & MockInterface $composer */
326-
$composer = $this->mockery(Composer::class, [
327-
'getPackage->getExtra' => [],
328-
]);
280+
$composerJsonPath = $this->fileSystem->tempnam(sys_get_temp_dir(), 'cc_', '.json');
281+
file_put_contents($composerJsonPath, json_encode([
282+
'extra' => [],
283+
]));
329284

330-
$finderTool = new class () {
285+
$finderTool = new class ($composerJsonPath) {
331286
use FinderTool;
332287

333-
public Composer $composer;
288+
public function __construct(private string $path)
289+
{
290+
}
334291

335-
public function getComposer(
336-
InputInterface $input,
337-
OutputInterface $output,
338-
Filesystem $filesystem,
339-
): Composer {
340-
return $this->composer;
292+
public function findComposerJson(Filesystem $filesystem): string
293+
{
294+
return $this->path;
341295
}
342296
};
343297

344-
$finderTool->composer = $composer;
345-
346298
/** @var Configuration $configuration */
347299
$configuration = $finderTool->findConfiguration($this->input, $this->output);
348300

349301
$this->assertMatchesSnapshot(json_encode($configuration), new WindowsSafeTextDriver());
302+
303+
@unlink($composerJsonPath);
350304
}
351305
}

0 commit comments

Comments
 (0)