Skip to content

Commit c01d1f2

Browse files
authored
[BUGFIX] Read local composer.json for init command (#871)
1 parent 8a9ad89 commit c01d1f2

File tree

8 files changed

+157
-59
lines changed

8 files changed

+157
-59
lines changed

packages/typo3-guides-cli/resources/templates/Index.md.twig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
{{ description | default('No description provided.') }}
44

5+
> [!NOTE]
6+
> This documentation guide was automatically created by the init command of
7+
> the TYPO3 Documentation Rendering Container. See
8+
> `Rendering container <https://docs.typo3.org/permalink/h2document:rendering>`_
9+
> for details.
10+
511
## Installation
612

713
Install the extension via Composer:

packages/typo3-guides-cli/resources/templates/guides.xml.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!-- See https://docs.typo3.org/permalink/h2document:guides-xml for documentation on this file-->
23
<guides
34
xmlns="https://www.phpdoc.org/guides"
45
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

packages/typo3-guides-cli/resources/templates/rst/Configuration.rst.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ See also: `TYPO3 Explained, Using a site set as dependency in a site <https://do
3030
Use the settings to configure the extension
3131
-------------------------------------------
3232

33-
.. typo3:site-set-settings:: PROJECT:/
33+
.. typo3:site-set-settings:: PROJECT:/{{ siteSetDefinition }}
3434
:name: main-set
3535
:type:
3636
:Label: max=30

packages/typo3-guides-cli/resources/templates/rst/Index.rst.twig

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
{{ description | default('No description provided.') }}
88

9+
.. note::
10+
This documentation guide was automatically created by the init command of
11+
the TYPO3 Documentation Rendering Container. See
12+
`Rendering container <https://docs.typo3.org/permalink/h2document:rendering>`_
13+
for details.
14+
915
.. toctree::
1016
:glob:
1117
:titlesonly:
@@ -24,24 +30,24 @@
2430
:class: pb-4
2531
:card-height: 100
2632

27-
.. card:: :ref:`Installation <installation>`
33+
.. card:: :ref:`Installation <installation>`
2834

29-
Explains how to install this extension in Composer-based and Classic
30-
TYPO3 installations.
35+
Explains how to install this extension in Composer-based and Classic
36+
TYPO3 installations.
3137

32-
.. card:: :ref:`Configuration <configuration>`
38+
.. card:: :ref:`Configuration <configuration>`
3339

34-
{% if siteSet %}
35-
Learn how to include the site set `{{ siteSet }}` and how to use settings
36-
to configure this extension.
37-
{% else %}
38-
Learn how to configure this extension.
39-
{% endif %}
40+
{% if siteSet %}
41+
Learn how to include the site set `{{ siteSet }}` and how to use settings
42+
to configure this extension.
43+
{% else %}
44+
Learn how to configure this extension.
45+
{% endif %}
4046

41-
.. card:: :ref:`Frequently Asked Questions (FAQ) <faq>`
47+
.. card:: :ref:`Frequently Asked Questions (FAQ) <faq>`
4248

43-
These questions have been frequently asked.
49+
These questions have been frequently asked.
4450

45-
.. card:: :ref:`How to get help <help>`
51+
.. card:: :ref:`How to get help <help>`
4652

47-
Learn where to get help and how to report issues you found.
53+
Learn where to get help and how to report issues you found.

packages/typo3-guides-cli/src/Command/InitCommand.php

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use T3Docs\GuidesCli\Generation\DocumentationGenerator;
1414
use T3Docs\VersionHandling\Packagist\ComposerPackage;
1515
use T3Docs\VersionHandling\Packagist\PackagistService;
16+
use T3Docs\VersionHandling\Typo3VersionMapping;
1617

1718
/**
1819
* You can run this command, for example like
@@ -57,7 +58,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
5758
}
5859

5960
if ($input->getOption('quiet')) {
60-
echo 'This command is interactive and requires user input.' . PHP_EOL;
61+
echo '<error>This command is interactive and requires user input. </error>' . PHP_EOL;
6162
return Command::INVALID;
6263
}
6364

@@ -66,12 +67,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int
6667
return Command::INVALID;
6768
}
6869

69-
$output->writeln('Welcome to the <comment>TYPO3 documentation</comment> project setup wizard');
70+
$output->writeln('Welcome to the <comment>TYPO3 documentation guide</comment> setup wizard');
7071
$output->writeln('This wizard will help you to create a new documentation project in the current directory (or work directory).');
7172
$output->writeln('');
7273

7374
$composerInfo = $this->getComposerInfo($output);
7475

76+
if ($composerInfo === null) {
77+
$output->writeln('<error>No composer.json was found in the current or work directory. Use option --working-dir to set the work directory.</error>');
78+
return Command::FAILURE;
79+
}
80+
7581
/** @var QuestionHelper $helper */
7682
$helper = $this->getHelper('question');
7783

@@ -87,7 +93,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8793
});
8894
$format = $helper->ask($input, $output, $question);
8995

90-
$projectNameQuestion = new Question(sprintf('What is the title of your documentation? <comment>[%s]</comment>: ', $composerInfo?->getComposerName()), $composerInfo?->getComposerName());
96+
$projectNameQuestion = new Question(
97+
sprintf('What is the title of your documentation? <comment>[%s]</comment>: ', $composerInfo->getComposerName()),
98+
$composerInfo->getComposerName()
99+
);
91100
$projectNameQuestion->setValidator(function ($answer) {
92101
if (is_null($answer) || trim($answer) === '') {
93102
throw new \RuntimeException('The project title cannot be empty.');
@@ -98,36 +107,45 @@ protected function execute(InputInterface $input, OutputInterface $output): int
98107
$projectName = $helper->ask($input, $output, $projectNameQuestion);
99108

100109
$question = $this->createValidatedUrlQuestion(
101-
sprintf('What is the URL of your project\'s homepage? <comment>[%s]</comment>: ', $composerInfo?->getHomepage()),
102-
$composerInfo?->getHomepage(),
103-
['https://extensions.typo3.org/package/' . $composerInfo?->getComposerName()]
110+
'What is the URL of your project\'s homepage? <comment>[%s]</comment>: ',
111+
[
112+
$composerInfo->getHomepage(),
113+
'https://extensions.typo3.org/package/' . $composerInfo->getExtensionKey(),
114+
]
104115
);
105116
$projectHomePage = $helper->ask($input, $output, $question);
106117

107118

108119
$question = $this->createValidatedUrlQuestion(
109-
sprintf(sprintf('What is the URL of your project\'s repository? <comment>[%s]</comment>', 'https://github.com/' . $composerInfo?->getComposerName()), 'https://github.com/' . $composerInfo?->getComposerName()),
110-
$composerInfo?->getHomepage(),
120+
'What is the URL of your project\'s repository? <comment>[%s]</comment>',
111121
[
112-
'https://github.com/' . $composerInfo?->getComposerName(),
113-
'https://gitlab.com/' . $composerInfo?->getComposerName(),
114-
$composerInfo?->getHomepage(),
122+
$composerInfo->getHomepage(),
123+
'https://github.com/' . $composerInfo->getComposerName(),
124+
'https://gitlab.com/' . $composerInfo->getComposerName(),
115125
]
116126
);
117127
$repositoryUrl = $helper->ask($input, $output, $question);
118128

119129
$question = $this->createValidatedUrlQuestion(
120-
sprintf('Where can users report issues? <comment>[%s]</comment>', $composerInfo?->getIssues()),
121-
$composerInfo?->getIssues(),
130+
'Where can users report issues? <comment>[%s]</comment>',
122131
[
123-
'https://github.com/' . $composerInfo?->getComposerName() . '/issues',
124-
'https://gitlab.com/' . $composerInfo?->getComposerName() . '/-/issues',
125-
$composerInfo?->getHomepage(),
132+
$composerInfo->getIssues(),
133+
$repositoryUrl . '/issues',
134+
$repositoryUrl . '/-/issues',
126135
]
127136
);
128137

129138
$issuesUrl = $helper->ask($input, $output, $question);
130-
$typo3CoreVersion = $helper->ask($input, $output, new Question('Which version of TYPO3 is the preferred version to use? <comment>[stable]</comment>: ', 'stable'));
139+
140+
// Get LTS versions from the Typo3VersionMapping class
141+
$ltsEnumCases = Typo3VersionMapping::getLtsVersions();
142+
143+
// Extract the values of these enum cases
144+
$ltsValues = array_map(static fn(Typo3VersionMapping $enumValue) => $enumValue->value, $ltsEnumCases);
145+
146+
$question = new Question('Which version of TYPO3 is the preferred version to use? <comment>[stable]</comment>: ', Typo3VersionMapping::getDefault()->value);
147+
$question->setAutocompleterValues([Typo3VersionMapping::Stable->value, Typo3VersionMapping::Dev->value, ...$ltsValues]);
148+
$typo3CoreVersion = $helper->ask($input, $output, $question);
131149

132150
$question = new Question('Do you want generate some Documentation? (yes/no) ', 'yes');
133151
$question->setValidator(function ($answer) {
@@ -184,8 +202,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
184202
'format' => $format,
185203
'useMd' => ($format === 'md'),
186204
'projectName' => $projectName,
187-
'description' => $composerInfo?->getDescription(),
188-
'composerName' => $composerInfo?->getComposerName(),
205+
'description' => $composerInfo->getDescription(),
206+
'composerName' => $composerInfo->getComposerName(),
189207
'projectHomePage' => $projectHomePage,
190208
'issuesUrl' => $issuesUrl,
191209
'repositoryUrl' => $repositoryUrl,
@@ -201,17 +219,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int
201219
}
202220

203221
/**
204-
* @param ?scalar $default
205222
* @param array<mixed> $autocompleteValues
206223
*/
207-
private function createValidatedUrlQuestion(string $questionText, mixed $default, array $autocompleteValues = []): Question
224+
private function createValidatedUrlQuestion(string $questionText, array $autocompleteValues = []): Question
208225
{
209-
$question = new Question($questionText, $default);
226+
$default = null;
227+
$autocompleteValuesFiltered = [];
228+
foreach ($autocompleteValues as $value) {
229+
if ($value !== null && $value !== '' && is_scalar($value)) {
230+
$default ??= (string)$value;
231+
$autocompleteValuesFiltered[] = (string)$value;
232+
}
233+
}
234+
$question = new Question(sprintf($questionText, $default), $default);
210235
if (!empty($autocompleteValues)) {
211-
$question->setAutocompleterValues($autocompleteValues);
236+
$question->setAutocompleterValues($autocompleteValuesFiltered);
212237
}
213238
$question->setValidator(function ($answer) {
214-
if (!is_null($answer) && !filter_var($answer, FILTER_VALIDATE_URL)) {
239+
if (!is_null($answer) && $answer !== '' && !filter_var($answer, FILTER_VALIDATE_URL)) {
215240
throw new \RuntimeException('The URL is not valid');
216241
}
217242
return $answer;
@@ -228,19 +253,16 @@ private function getComposerInfo(OutputInterface $output): ComposerPackage|null
228253
}
229254

230255
$output->writeln('A <comment>composer.json</comment> file was found in the current directory.');
231-
$packageName = $this->fetchComposerPackageName();
232-
if (!is_string($packageName)) {
233-
$output->writeln('The package name could not be determined from the <comment>composer.json</comment> file.');
234-
return null;
235-
}
236256

237-
$composerInfo = (new PackagistService())->getComposerInfo($packageName);
238-
$output->writeln(sprintf('The package <comment>%s</comment> was found on packagist.org', $composerInfo->getComposerName()));
257+
$composerInfo = (new PackagistService())->getComposerInfoFromJson($this->fetchComposerArray() ?? []);
239258

240259
return $composerInfo;
241260
}
242261

243-
private function fetchComposerPackageName(): string|null
262+
/**
263+
* @return array<string, mixed>|null
264+
*/
265+
private function fetchComposerArray(): array|null
244266
{
245267
$fileContent = file_get_contents('composer.json');
246268
if ($fileContent === false) {
@@ -253,7 +275,7 @@ private function fetchComposerPackageName(): string|null
253275
return null;
254276
}
255277

256-
return $composerJson['name'];
278+
return $composerJson;
257279
}
258280

259281
}

packages/typo3-version-handling/src/Packagist/ComposerPackage.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public function __construct(
1515
private readonly string $issues = '',
1616
private readonly string $source = '',
1717
private readonly bool $development = false,
18+
private readonly string $type = '',
19+
private readonly string $extensionKey = '',
1820
) {}
1921

2022
public function getComposerName(): string
@@ -66,4 +68,14 @@ public function isDevelopment(): bool
6668
{
6769
return $this->development;
6870
}
71+
72+
public function getType(): string
73+
{
74+
return $this->type;
75+
}
76+
77+
public function getExtensionKey(): string
78+
{
79+
return $this->extensionKey;
80+
}
6981
}

packages/typo3-version-handling/src/Packagist/PackagistService.php

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,65 @@ public function getComposerInfo(string $composerName): ComposerPackage
2727
return $this->cache[$composerName];
2828
}
2929
$packageVersionData = $packageData['packages'][$composerName][0];
30+
31+
$this->cache[$composerName] = $this->getComposerInfoFromJson(
32+
$packageVersionData,
33+
'found',
34+
'https://packagist.org/packages/' . $composerName
35+
);
36+
return $this->cache[$composerName];
37+
}
38+
39+
/**
40+
* @param array<string, mixed> $composerJsonArray Content of the composer.json as array
41+
*/
42+
public function getComposerInfoFromJson(array $composerJsonArray, string $packagistStatus = '', string $packagistUrl = ''): ComposerPackage
43+
{
44+
$composerName = $composerJsonArray['name'] ?? null;
45+
if (!is_string($composerName)) {
46+
throw new \Exception('composer.json does not contain key "name". Invalid composer.json');
47+
}
3048
$isDev = false;
31-
$keywords = $packageVersionData['keywords'] ?? [];
49+
$keywords = $composerJsonArray['keywords'] ?? [];
50+
if (!is_array($keywords)) {
51+
$keywords = [];
52+
}
3253
if (in_array('testing', $keywords, true) || in_array('development', $keywords, true)) {
3354
$isDev = true;
3455
}
3556

36-
$this->cache[$composerName] = new ComposerPackage(
57+
$support = $composerJsonArray['support'] ?? [];
58+
$docsUrl = $this->getString(is_array($support) ? ($support['docs'] ?? '') : '');
59+
$issuesUrl = $this->getString(is_array($support) ? ($support['issues'] ?? '') : '');
60+
$sourceUrl = $this->getString(is_array($support) ? ($support['source'] ?? '') : '');
61+
$extensionKey = '';
62+
if (is_array($composerJsonArray['extra']) && $composerJsonArray['extra']['typo3/cms']) {
63+
$extensionKey = $this->getString($composerJsonArray['extra']['typo3/cms']['extension-key'] ?? '');
64+
}
65+
66+
$composerPackage = new ComposerPackage(
3767
$composerName,
3868
'composer req ' . ($isDev ? '--dev ' : '') . $composerName,
39-
'found',
40-
'https://packagist.org/packages/' . $composerName,
41-
$packageVersionData['description'] ?? '',
42-
$packageVersionData['homepage'] ?? '',
43-
$packageVersionData['support']['docs'] ?? '',
44-
$packageVersionData['support']['issues'] ?? '',
45-
$packageVersionData['support']['source'] ?? '',
46-
$isDev
69+
$packagistStatus,
70+
$packagistUrl,
71+
$this->getString($composerJsonArray['description'] ?? ''),
72+
$this->getString($composerJsonArray['homepage'] ?? ''),
73+
$docsUrl,
74+
$issuesUrl,
75+
$sourceUrl,
76+
$isDev,
77+
$this->getString($composerJsonArray['type'] ?? ''),
78+
$extensionKey,
4779
);
48-
return $this->cache[$composerName];
80+
return $composerPackage;
81+
}
82+
83+
private function getString(mixed $value, string $default = ''): string
84+
{
85+
if (is_scalar($value)) {
86+
return (string)$value;
87+
}
88+
return $default;
4989
}
5090

5191

packages/typo3-version-handling/src/Typo3VersionMapping.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ public function getVersion(): string
3838
};
3939
}
4040

41+
/**
42+
* @return Typo3VersionMapping[]
43+
*/
44+
public static function getLtsVersions(): array
45+
{
46+
return [
47+
Typo3VersionMapping::V13,
48+
Typo3VersionMapping::V12,
49+
];
50+
}
51+
4152
public static function getDefault(): Typo3VersionMapping
4253
{
4354
return Typo3VersionMapping::Stable;

0 commit comments

Comments
 (0)