Skip to content
Open
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
1 change: 0 additions & 1 deletion .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ TYPO3_API_VERSION=v1
TYPO3_API_TOKEN=
TYPO3_API_USERNAME=
TYPO3_API_PASSWORD=
TYPO3_EXTENSION_KEY=
TYPO3_EXCLUDE_FROM_PACKAGING=
TYPO3_DISABLE_DOCS_VERSION_UPDATE=
71 changes: 38 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,13 @@ TYPO3_API_PASSWORD=<your-t3o-password>
Example:

```bash
TYPO3_API_TOKEN="someToken" TYPO3_EXTENSION_KEY="ext_key" bin/tailor ter:details
TYPO3_API_TOKEN="someToken" bin/tailor ter:details ext_key
```

This will display the extension details for extension `ext_key` if
`someToken` is valid (not expired/revoked and having at least the
`extension:read` scope assigned).
`extension:read` scope assigned). The extension key can also be read
automatically from your `composer.json` if defined there.

## Installation

Expand All @@ -91,22 +92,23 @@ option. If set, the raw result will be returned. This can be
used for further processing e.g. by using some JSON processor.

Most of the commands require an extension key to work with.
There are multiple possibilities to provide an extension key.
These are - in the order in which they are checked:
The extension key is determined in the following order:

- As argument, e.g. `./vendor/bin/tailor ter:details my_key`
- As environment variable, `TYPO3_EXTENSION_KEY=my_key`
- In your `composer.json`, `[extra][typo3/cms][extension-key] = 'my_key'`
1. **CLI argument** (highest priority): e.g. `./vendor/bin/tailor ter:details my_key`
2. **composer.json** (recommended): `[extra][typo3/cms][extension-key] = 'my_key'`
3. **Environment variable** (deprecated, for backwards compatibility only): `TYPO3_EXTENSION_KEY=my_key`

This means, even if you have an extension key defined globally,
either as environment variable or in your `composer.json`, you
can still run all commands for different extensions by adding
> [!WARNING]
> Using the `TYPO3_EXTENSION_KEY` environment variable is deprecated and will
> trigger a deprecation warning. Please migrate to using `composer.json` instead.

This means, even if you have an extension key defined in your `composer.json`,
you can still run commands for different extensions by providing
the desired extension key as argument to the command.

> [!NOTE]
> If no extension key is defined, neither as an argument,
> as environment variable, nor in your `composer.json`, commands
> which require an extension key to be set, will throw an exception.
> If no extension key is defined, neither as an argument nor in your
> `composer.json`, commands which require an extension key will throw an exception.

### Manage your personal access token

Expand Down Expand Up @@ -481,15 +483,17 @@ This can either be done using **Step 3** from above example
or by creating a new GitHub release which will also add a
new tag.

The workflow furthermore requires the GitHub secrets `TYPO3_EXTENSION_KEY`
and `TYPO3_API_TOKEN` to be set. Add them at "Settings -> Secrets -> New
repository secret".
The workflow requires the GitHub secret `TYPO3_API_TOKEN` to be set.
Add it at "Settings -> Secrets -> New repository secret".

> [!NOTE]
> If your `composer.json` file contains the extension key at
> `[extra][typo3/cms][extension-key] = 'my_key'` (this is good practice anyway),
> the `TYPO3_EXTENSION_KEY` secret and assignment in the below GitHub action
> example is not needed, tailor will pick it up.
> [!IMPORTANT]
> The extension key has to be defined in your `composer.json` at
> `[extra][typo3/cms][extension-key]`.
>
> For backwards compatibility, `TYPO3_EXTENSION_KEY` is still supported but
> deprecated. It should not be used as it prevents a single source of truth
> and causes error messages to be masked in CI logs (e.g.
> `"Could not publish extension ***"`), hiding valuable information.

The version is automatically fetched from the tag and
validated to match the required pattern.
Expand All @@ -514,7 +518,6 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-20.04
env:
TYPO3_EXTENSION_KEY: ${{ secrets.TYPO3_EXTENSION_KEY }}
TYPO3_API_TOKEN: ${{ secrets.TYPO3_API_TOKEN }}
steps:
- name: Checkout repository
Expand All @@ -539,7 +542,7 @@ jobs:
readonly local comment=$(git tag -l ${{ env.version }} --format '%(contents))

if [[ -z "${comment// }" ]]; then
echo "comment=Released version ${{ env.version }} of ${{ env.TYPO3_EXTENSION_KEY }}" >> $GITHUB_ENV
echo "comment=Released version ${{ env.version }}" >> $GITHUB_ENV
else
{
echo 'comment<<EOF'
Expand Down Expand Up @@ -595,14 +598,16 @@ corresponding [README][typo3-uploader-ter-readme].
The job will only be executed when pushing a new tag.
The upload comment is taken from the message in the tag.

The job furthermore requires the GitLab variables
`TYPO3_EXTENSION_KEY` and `TYPO3_API_TOKEN` to be set.
The job requires the GitLab variable `TYPO3_API_TOKEN` to be set.

> [!NOTE]
> If your `composer.json` file contains your extension
> key, you can remove the `TYPO3_EXTENSION_KEY` variable, the
> check and the assignment in the GitLab pipeline, since Tailor
> automatically fetches this key then.
> [!IMPORTANT]
> The extension key has to be defined in your `composer.json` at
> `[extra][typo3/cms][extension-key]`.
>
> For backwards compatibility, `TYPO3_EXTENSION_KEY` is still supported but
> deprecated. It should not be used as it prevents a single source of truth
> and causes error messages to be masked in CI logs (e.g.
> `"Could not publish extension ***"`), hiding valuable information.

The variable `CI_COMMIT_TAG` is set by GitLab automatically.

Expand All @@ -616,14 +621,14 @@ The variable `CI_COMMIT_TAG` is set by GitLab automatically.
- composer global require typo3/tailor
script:
- >
if [ -n "$CI_COMMIT_TAG" ] && [ -n "$TYPO3_API_TOKEN" ] && [ -n "$TYPO3_EXTENSION_KEY" ]; then
if [ -n "$CI_COMMIT_TAG" ] && [ -n "$TYPO3_API_TOKEN" ]; then
echo -e "Preparing upload of release ${CI_COMMIT_TAG} to TER\n"
# Cleanup before we upload
git reset --hard HEAD && git clean -fx
# Upload
# Upload (extension key is read from composer.json)
TAG_MESSAGE=`git tag -n10 -l $CI_COMMIT_TAG | sed 's/^[0-9.]*[ ]*//g'`
echo "Uploading release ${CI_COMMIT_TAG} to TER"
/tmp/vendor/bin/tailor ter:publish --comment "$TAG_MESSAGE" "$CI_COMMIT_TAG" "$TYPO3_EXTENSION_KEY"
/tmp/vendor/bin/tailor ter:publish --comment "$TAG_MESSAGE" "$CI_COMMIT_TAG"
fi;
```

Expand Down
31 changes: 21 additions & 10 deletions src/Helper/CommandHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,32 @@ final class CommandHelper
{
public static function getExtensionKeyFromInput(InputInterface $input): string
{
// 1. CLI argument has highest priority
if ($input->hasArgument('extensionkey')
&& ($key = ($input->getArgument('extensionkey') ?? '')) !== ''
) {
$extensionKey = $key;
} elseif (Variables::has('TYPO3_EXTENSION_KEY')) {
$extensionKey = Variables::get('TYPO3_EXTENSION_KEY');
} elseif (($extensionKeyFromComposer = (new ComposerReader())->getExtensionKey()) !== '') {
$extensionKey = $extensionKeyFromComposer;
} else {
throw new ExtensionKeyMissingException(
'The extension key must either be set as argument, as environment variable or in the composer.json.',
1605706548
return $key;
}

// 2. composer.json is the recommended source
$extensionKeyFromComposer = (new ComposerReader())->getExtensionKey();
if ($extensionKeyFromComposer !== '') {
return $extensionKeyFromComposer;
}

// 3. Environment variable only for backwards compatibility
if (Variables::has('TYPO3_EXTENSION_KEY')) {
trigger_error(
'Using TYPO3_EXTENSION_KEY environment variable is deprecated. '
. 'Please set the extension key in composer.json at [extra][typo3/cms][extension-key] instead.',
E_USER_DEPRECATED
);
return Variables::get('TYPO3_EXTENSION_KEY');
}

return $extensionKey;
throw new ExtensionKeyMissingException(
'The extension key must either be set as argument or in composer.json at [extra][typo3/cms][extension-key].',
1605706548
);
}
}
31 changes: 25 additions & 6 deletions tests/Unit/Helper/CommandHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@ protected function setUp(): void
$this->input = new ArrayInput([], $this->definition);
}

protected function tearDown(): void
{
// Clean up environment variable after each test
putenv('TYPO3_EXTENSION_KEY');
}

/**
* @test
*/
public function getExtensionKeyFromInputThrowsExceptionIfInputHasNoArgumentDefined(): void
{
$this->expectException(ExtensionKeyMissingException::class);
$this->expectExceptionMessage('The extension key must either be set as argument, as environment variable or in the composer.json.');
$this->expectExceptionMessage('The extension key must either be set as argument or in composer.json at [extra][typo3/cms][extension-key].');
$this->expectExceptionCode(1605706548);

CommandHelper::getExtensionKeyFromInput($this->input);
Expand All @@ -66,7 +72,7 @@ public function getExtensionKeyFromInputReturnsExtensionKeyFromInputArgument():
public function getExtensionKeyFromInputIgnoresEmptyInputArgumentValue(): void
{
$this->expectException(ExtensionKeyMissingException::class);
$this->expectExceptionMessage('The extension key must either be set as argument, as environment variable or in the composer.json.');
$this->expectExceptionMessage('The extension key must either be set as argument or in composer.json at [extra][typo3/cms][extension-key].');
$this->expectExceptionCode(1605706548);

$this->definition->addArgument(new InputArgument('extensionkey', InputArgument::OPTIONAL));
Expand All @@ -78,12 +84,25 @@ public function getExtensionKeyFromInputIgnoresEmptyInputArgumentValue(): void
/**
* @test
*/
public function getExtensionKeyFromInputReturnsExtensionKeyFromEnvironmentVariables(): void
public function getExtensionKeyFromInputReturnsExtensionKeyFromEnvironmentVariablesWithDeprecation(): void
{
putenv('TYPO3_EXTENSION_KEY=foo');

self::assertSame('foo', CommandHelper::getExtensionKeyFromInput($this->input));

putenv('TYPO3_EXTENSION_KEY');
$deprecationTriggered = false;
set_error_handler(static function (int $errno, string $errstr) use (&$deprecationTriggered): bool {
if ($errno === E_USER_DEPRECATED) {
$deprecationTriggered = true;
self::assertStringContainsString('TYPO3_EXTENSION_KEY environment variable is deprecated', $errstr);
return true;
}
return false;
});

try {
self::assertSame('foo', CommandHelper::getExtensionKeyFromInput($this->input));
self::assertTrue($deprecationTriggered, 'Expected deprecation warning was not triggered');
} finally {
restore_error_handler();
}
}
}