Skip to content

Instantly share code, notes, and snippets.

@mikestreety
Last active October 14, 2025 08:18
Show Gist options
  • Save mikestreety/3ab51877065ce35ccba755e63944deff to your computer and use it in GitHub Desktop.
Save mikestreety/3ab51877065ce35ccba755e63944deff to your computer and use it in GitHub Desktop.
Set up linting for TYPO3 extensions
#!/usr/bin/env php
<?php
/**
* TYPO3 Extension Linting Setup Script
*
* This script sets up a TYPO3 extension for linting by:
* - Adding .gitignore file
* - Modifying composer.json with linting dependencies and scripts
*/
// File content templates
$gitignoreContent = ".cache/\n.Build\ncomposer.lock\n";
if ($argc < 2) {
echo "Usage: php setup-extension-linting.php <extension-folder-path>\n";
exit(1);
}
$extensionPath = rtrim($argv[1], '/');
// Validate extension folder exists
if (!is_dir($extensionPath)) {
echo "Error: Extension folder '$extensionPath' does not exist.\n";
exit(1);
}
// Validate composer.json exists
$composerJsonPath = $extensionPath . '/composer.json';
if (!file_exists($composerJsonPath)) {
echo "Error: composer.json not found in '$extensionPath'.\n";
exit(1);
}
echo "Setting up TYPO3 extension linting for: $extensionPath\n";
/**
* Create .gitignore file
*/
function createGitIgnore($extensionPath)
{
global $gitignoreContent;
$gitignorePath = $extensionPath . '/.gitignore';
file_put_contents($gitignorePath, $gitignoreContent);
echo "✓ Created .gitignore\n";
}
/**
* Modify composer.json with testing configuration
*/
function modifyComposerJson($extensionPath, $composer)
{
$composerJsonPath = $extensionPath . '/composer.json';
// Add extra
if (!isset($composer['extra'])) {
$composer['extra'] = [];
}
if (!isset($composer['extra']['typo3/cms'])) {
$composer['extra']['typo3/cms'] = [];
}
$composer['extra']['typo3/cms']['web-dir'] = ".Build/public";
// Add require-dev
if (!isset($composer['require-dev'])) {
$composer['require-dev'] = [];
}
$requireDev = [
"ergebnis/composer-normalize" => "^2.48",
"lintkit/editorconfig-config" => "^1.0",
"lintkit/php-coding-standards-config" => "^2.0",
"php-parallel-lint/php-parallel-lint" => "^1.4",
];
foreach ($requireDev as $package => $version) {
if (!isset($composer['require-dev'][$package])) {
$composer['require-dev'][$package] = $version;
}
}
// Add config
if (!isset($composer['config'])) {
$composer['config'] = [];
}
$composer['config']['lock'] = false;
$composer['config']['vendor-dir'] = ".Build/vendor";
if (!isset($composer['config']['allow-plugins'])) {
$composer['config']['allow-plugins'] = [];
}
$composer['config']['allow-plugins']['typo3/cms-composer-installers'] = true;
$composer['config']['allow-plugins']['typo3/class-alias-loader'] = true;
// Add scripts
if (!isset($composer['scripts'])) {
$composer['scripts'] = [];
}
$scripts = [
"clean" => "rm -rf .Build",
"composer-normalize:dry-run" => "@composer-normalize:fix --dry-run",
"composer-normalize:fix" => "@composer normalize --indent-size 4 --indent-style space",
"editorconfig:dry-run" => "ec --finder-config .Build/vendor/lintkit/editorconfig-config/ec-cli-config.php",
"editorconfig:fix" => "@editorconfig:dry-run --fix",
"lint" => [
"@lint:php",
"@composer-normalize:fix",
"@yaml-lint",
"@editorconfig:fix",
],
"lint:php" => [
"@parallel-lint",
"@php-cs-fixer:fix",
],
"parallel-lint" => "parallel-lint ./ --exclude ./.Build",
"php-cs-fixer:dry-run" => "@php-cs-fixer:fix --dry-run",
"php-cs-fixer:fix" => "php-cs-fixer fix --config .Build/vendor/lintkit/php-coding-standards-config/.php-cs-fixer.php -v --diff",
"yaml-lint" => "yaml-lint ./Configuration",
];
foreach ($scripts as $name => $command) {
$composer['scripts'][$name] = $command;
}
// Write back to file
$newContent = json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
file_put_contents($composerJsonPath, $newContent);
echo "✓ Modified composer.json\n";
}
// Main execution
try {
// Load and parse composer.json first
$composerJsonPath = $extensionPath . '/composer.json';
$content = file_get_contents($composerJsonPath);
$composer = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("Invalid JSON in composer.json: " . json_last_error_msg());
}
createGitIgnore($extensionPath);
modifyComposerJson($extensionPath, $composer);
echo "\n✅ Extension linting setup completed successfully!\n";
echo "\nNext steps:\n";
echo "1. Run 'composer install' in the extension folder\n";
echo "2. Run 'composer lint'\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment