diff --git a/.github/workflows/code-standards.yml b/.github/workflows/code-standards.yml new file mode 100644 index 0000000..84190e5 --- /dev/null +++ b/.github/workflows/code-standards.yml @@ -0,0 +1,58 @@ +name: PHP Code Standards + +on: + workflow_call: + inputs: + version: + type: string + default: "^3.0" + config: + type: string + default: "" + path: + type: string + default: "." + rules: + type: string + default: | + { + "@PSR2": true, + "array_syntax": {"syntax":"short"}, + "concat_space": {"spacing":"one"}, + "no_unused_imports": true, + "ordered_imports": true, + "new_with_parentheses": true, + "whitespace_after_comma_in_array": true, + "method_argument_space": { + "keep_multiple_spaces_after_comma": true, + "on_multiline": "ignore" + }, + "return_type_declaration": {"space_before": "none"}, + "single_quote": true + } + +permissions: + contents: read + +jobs: + php_code_standards: + runs-on: ubuntu-latest + name: PHP Code Standards + steps: + - uses: actions/checkout@v4 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + - name: Run PHP CS Fixer + run: | + composer global require friendsofphp/php-cs-fixer:${{ inputs.version }} -q + CONFIG="${{ inputs.config }}" + RULES=$(echo $'${{ inputs.rules }}'|tr -d '\n\t\r ') + + set -x + + ~/.composer/vendor/bin/php-cs-fixer fix \ + ${{ inputs.path }} \ + $(if [ ! -z "$CONFIG" ]; then echo "--config=$CONFIG"; elif [ ! -z "$RULES" ]; then echo --rules=$RULES; fi) \ + --dry-run --diff diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..880fd88 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,33 @@ +name: PHP Static Analysis +on: + workflow_call: + inputs: + version: + type: string + default: "^1.8" + paths: + type: string + default: "src" + autoload-file: + type: string + default: "vendor/autoload.php" + +permissions: + contents: read + +jobs: + static_analysis: + runs-on: ubuntu-latest + name: PHPStan Static Analysis + steps: + - uses: actions/checkout@v4 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + - name: Run Script + run: | + composer install -q + composer global require phpstan/phpstan:${{ inputs.version }} -q + ~/.composer/vendor/bin/phpstan analyse ${{ inputs.paths }} \ + --autoload-file=${{ inputs.autoload-file }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index becf09a..8243c8c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,20 +31,11 @@ jobs: - name: Run Script run: vendor/bin/phpunit - style: - runs-on: ubuntu-latest - name: PHP Style Check - steps: - - uses: actions/checkout@v4 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - - name: Install Dependencies - uses: nick-invision/retry@v3 - with: - timeout_minutes: 10 - max_attempts: 3 - command: composer install - - name: Run Script - run: vendor/bin/php-cs-fixer fix . + code-standards: + uses: ./.github/workflows/code-standards.yml + with: + path: src + + static-analysis: + uses: ./.github/workflows/static-analysis.yml + diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php deleted file mode 100644 index 0026c58..0000000 --- a/.php-cs-fixer.dist.php +++ /dev/null @@ -1,16 +0,0 @@ -setRules([ - '@PSR2' => true, - 'concat_space' => ['spacing' => 'one'], - 'no_unused_imports' => true, - 'method_argument_space' => false, - ]) - ->setFinder( - PhpCsFixer\Finder::create()->in(__DIR__) - ) -; - -return $config; diff --git a/composer.json b/composer.json index eefcb4d..5b494b5 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "paragonie/random_compat": ">=2", "phpunit/phpunit": "^9", "phpspec/prophecy-phpunit": "^2.0", - "friendsofphp/php-cs-fixer": "^3.21", + "friendsofphp/php-cs-fixer": "^3.62", "google/cloud-dlp": "^1.10", "google/cloud-storage": "^1.33", "google/cloud-secret-manager": "^1.12" diff --git a/src/Fixers/ClientUpgradeFixer/ClientUpgradeFixer.php b/src/Fixers/ClientUpgradeFixer/ClientUpgradeFixer.php index 7adf779..9f35570 100644 --- a/src/Fixers/ClientUpgradeFixer/ClientUpgradeFixer.php +++ b/src/Fixers/ClientUpgradeFixer/ClientUpgradeFixer.php @@ -3,23 +3,21 @@ namespace Google\Cloud\Fixers\ClientUpgradeFixer; use PhpCsFixer\AbstractFixer; -use PhpCsFixer\Fixer\FixerInterface; +use PhpCsFixer\Fixer\ConfigurableFixerInterface; +use PhpCsFixer\Fixer\ConfigurableFixerTrait; use PhpCsFixer\Fixer\Import\OrderedImportsFixer; +use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; +use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; +use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; +use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; -use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer; -use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis; -use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; -use ReflectionClass; -use ReflectionMethod; -use PhpCsFixer\Fixer\ConfigurableFixerInterface; -use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; -use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; -use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; class ClientUpgradeFixer extends AbstractFixer implements ConfigurableFixerInterface { + use ConfigurableFixerTrait; + /** * Check if the fixer is a candidate for given Tokens collection. * @@ -34,19 +32,10 @@ public function isCandidate(Tokens $tokens): bool return true; } - /** - * @param array $configuration - */ - public function configure(array $configuration): void - { - // no configuration assumes true - $this->configuration = $configuration; - } - /** * Defines the available configuration options of the fixer. */ - public function getConfigurationDefinition(): FixerConfigurationResolverInterface + protected function createConfigurationDefinition(): FixerConfigurationResolverInterface { return new FixerConfigurationResolver([ (new FixerOptionBuilder('clientVars', 'A map of client variables to their new class names')) @@ -199,10 +188,10 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void $importedClasses = array_map(fn ($useDeclaration) => $useDeclaration->getFullName(), $useDeclarations); $classesToImport = array_filter( $classesToImport, - fn($requestClass) => !isset($importedClasses[$requestClass->getName()]) + fn ($requestClass) => !isset($importedClasses[$requestClass->getName()]) ); $requestClassImportTokens = array_map( - fn($requestClass) => $requestClass->getImportTokens(), + fn ($requestClass) => $requestClass->getImportTokens(), array_values($classesToImport) ); $tokens->insertAt($importStart, array_merge(...$requestClassImportTokens)); diff --git a/src/Fixers/ClientUpgradeFixer/RequestClass.php b/src/Fixers/ClientUpgradeFixer/RequestClass.php index 78ca769..89c78a2 100644 --- a/src/Fixers/ClientUpgradeFixer/RequestClass.php +++ b/src/Fixers/ClientUpgradeFixer/RequestClass.php @@ -3,7 +3,6 @@ namespace Google\Cloud\Fixers\ClientUpgradeFixer; use PhpCsFixer\Tokenizer\Token; -use PhpCsFixer\Tokenizer\Tokens; use ReflectionClass; class RequestClass diff --git a/src/Fixers/ClientUpgradeFixer/RequestVariableCounter.php b/src/Fixers/ClientUpgradeFixer/RequestVariableCounter.php index 6f7dcc5..07fbf8e 100644 --- a/src/Fixers/ClientUpgradeFixer/RequestVariableCounter.php +++ b/src/Fixers/ClientUpgradeFixer/RequestVariableCounter.php @@ -2,8 +2,6 @@ namespace Google\Cloud\Fixers\ClientUpgradeFixer; -use PhpCsFixer\Tokenizer\Tokens; - class RequestVariableCounter { private array $varCounts = []; diff --git a/src/Fixers/ClientUpgradeFixer/RpcMethod.php b/src/Fixers/ClientUpgradeFixer/RpcMethod.php index 9f3b109..6dca677 100644 --- a/src/Fixers/ClientUpgradeFixer/RpcMethod.php +++ b/src/Fixers/ClientUpgradeFixer/RpcMethod.php @@ -6,7 +6,6 @@ use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; use ReflectionMethod; -use ReflectionParameter; class RpcMethod { diff --git a/src/TestUtils/CloudFunctionDeploymentTrait.php b/src/TestUtils/CloudFunctionDeploymentTrait.php index 2426639..2363ab2 100644 --- a/src/TestUtils/CloudFunctionDeploymentTrait.php +++ b/src/TestUtils/CloudFunctionDeploymentTrait.php @@ -142,7 +142,7 @@ public function setUpClient() public function getBaseUri() { - return self::$fn->getBaseUrl(getenv("GOOGLE_SKIP_DEPLOYMENT") === 'true'); + return self::$fn->getBaseUrl(getenv('GOOGLE_SKIP_DEPLOYMENT') === 'true'); } /** diff --git a/src/TestUtils/CloudSqlProxyTrait.php b/src/TestUtils/CloudSqlProxyTrait.php index f98014e..617a4e9 100644 --- a/src/TestUtils/CloudSqlProxyTrait.php +++ b/src/TestUtils/CloudSqlProxyTrait.php @@ -17,8 +17,8 @@ namespace Google\Cloud\TestUtils; -use Symfony\Component\Process\Process; use Exception; +use Symfony\Component\Process\Process; /** * Trait CloudSqlTestTrait diff --git a/src/TestUtils/FileUtil.php b/src/TestUtils/FileUtil.php index a76d248..8df98fa 100644 --- a/src/TestUtils/FileUtil.php +++ b/src/TestUtils/FileUtil.php @@ -23,7 +23,7 @@ class FileUtil { public static function randomName($length) { - $array = array(); + $array = []; for ($i = 0; $i < $length; ++$i) { array_push($array, chr(random_int(ord('a'), ord('z')))); } diff --git a/src/TestUtils/GcloudWrapper/AppEngine.php b/src/TestUtils/GcloudWrapper/AppEngine.php index 333ecde..1d3702f 100644 --- a/src/TestUtils/GcloudWrapper/AppEngine.php +++ b/src/TestUtils/GcloudWrapper/AppEngine.php @@ -237,4 +237,5 @@ public function getBaseUrl($service = 'default') } } +// @phpstan-ignore-next-line class_alias(AppEngine::class, \Google\Cloud\TestUtils\GcloudWrapper::class); diff --git a/src/TestUtils/GcloudWrapper/CloudFunction.php b/src/TestUtils/GcloudWrapper/CloudFunction.php index a6ca92e..ba1667d 100644 --- a/src/TestUtils/GcloudWrapper/CloudFunction.php +++ b/src/TestUtils/GcloudWrapper/CloudFunction.php @@ -17,9 +17,9 @@ namespace Google\Cloud\TestUtils\GcloudWrapper; -use Symfony\Component\Process\Process; -use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\PhpExecutableFinder; +use Symfony\Component\Process\Process; /** * Class CloudFunction. @@ -108,7 +108,7 @@ public static function fromArray(array $arr) $args[] = $arr[$key] ?? ''; } - return new static(...$args); + return new self(...$args); } /** diff --git a/src/TestUtils/GcloudWrapper/CloudRun.php b/src/TestUtils/GcloudWrapper/CloudRun.php index 0900185..55d6134 100644 --- a/src/TestUtils/GcloudWrapper/CloudRun.php +++ b/src/TestUtils/GcloudWrapper/CloudRun.php @@ -77,7 +77,7 @@ public function __construct($project, array $options = []) * * @return bool true if deployment suceeds, false upon failure */ - public function build($image, array $options = [], string $source = ".") + public function build($image, array $options = [], string $source = '.') { // Set default optioins $options = array_merge([ diff --git a/src/TestUtils/GcloudWrapper/GcloudWrapperTrait.php b/src/TestUtils/GcloudWrapper/GcloudWrapperTrait.php index d04f7a3..953757f 100644 --- a/src/TestUtils/GcloudWrapper/GcloudWrapperTrait.php +++ b/src/TestUtils/GcloudWrapper/GcloudWrapperTrait.php @@ -17,8 +17,8 @@ namespace Google\Cloud\TestUtils\GcloudWrapper; -use Symfony\Component\Process\Process; use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; /** * Trait GcloudWrapperTrait. @@ -89,7 +89,7 @@ protected function execWithRetry($cmd, $retries = 3, &$output = null) */ protected function runWithRetry(Process $cmd, $retries = 3) { - $this->errorLog('Running: ' . str_replace("'", "", $cmd->getCommandLine())); + $this->errorLog('Running: ' . str_replace("'", '', $cmd->getCommandLine())); for ($i = 0; $i <= $retries; ++$i) { // TODO: Use ExponentialBackoffTrait for more sophisticated handling. // Simple geometric backoff, .25 seconds * iteration. diff --git a/src/Utils/ContainerExec.php b/src/Utils/ContainerExec.php index 9e6b95c..c150b57 100644 --- a/src/Utils/ContainerExec.php +++ b/src/Utils/ContainerExec.php @@ -62,7 +62,8 @@ public function __construct( throw new \InvalidArgumentException("$workdir is not a directory"); } $this->gcloud = ($gcloud == null) ? new Gcloud() : $gcloud; - if (class_exists(\Twig_Loader_Filesystem::class)) { + if (class_exists(\Twig_Loader_Filesystem::class) + && class_exists(\Twig_Environment::class)) { $loader = new \Twig_Loader_Filesystem(__DIR__ . '/templates'); $this->twig = new \Twig_Environment($loader); } else { @@ -109,7 +110,7 @@ public function run() implode(PHP_EOL, $cmdOutput) ); if ($result !== 0) { - throw new \RuntimeException("Failed to run the command"); + throw new \RuntimeException('Failed to run the command'); } $ret = ''; if ($this->cloudSqlInstances) { diff --git a/src/Utils/Flex/FlexExecCommand.php b/src/Utils/Flex/FlexExecCommand.php index d60a60e..91da3c2 100644 --- a/src/Utils/Flex/FlexExecCommand.php +++ b/src/Utils/Flex/FlexExecCommand.php @@ -24,8 +24,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Exception\IOExceptionInterface; +use Symfony\Component\Filesystem\Filesystem; /** * CLI command for running a command with an image deployed to App Engine @@ -151,7 +151,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } $output->writeln("Using workdir: $workdir"); if ($preserveWorkdir) { - $output->writeln("Preserving the workdir"); + $output->writeln('Preserving the workdir'); } else { register_shutdown_function(function () use ($workdir, $fs) { $fs->remove($workdir); @@ -213,7 +213,7 @@ protected function resolveImage( 'describe', $version, "--service=$service", - "--format=json" + '--format=json' ] ); if ($ret !== 0) { @@ -244,7 +244,7 @@ protected function resolveImage( * @param string $service * @param InputInterface $input * @param OutputInterface $output - * @return string The version for the latest deployment for the given + * @return ?string The version for the latest deployment for the given * service. */ protected function detectLatestDeployedVersion( @@ -258,9 +258,9 @@ protected function detectLatestDeployedVersion( 'versions', 'list', "--service=$service", - "--format=get(version.id)", - "--sort-by=~version.createTime", - "--limit=1" + '--format=get(version.id)', + '--sort-by=~version.createTime', + '--limit=1' ] ); if (!empty($cmdOutput)) { diff --git a/src/Utils/Gcloud.php b/src/Utils/Gcloud.php index 59e350f..8f61bb6 100644 --- a/src/Utils/Gcloud.php +++ b/src/Utils/Gcloud.php @@ -28,7 +28,7 @@ class Gcloud public function __construct() { $auths = exec( - escapeshellcmd("gcloud auth list --format=value(account)"), + escapeshellcmd('gcloud auth list --format=value(account)'), $output, $ret ); diff --git a/src/Utils/Project.php b/src/Utils/Project.php index 7a315ca..a34c192 100644 --- a/src/Utils/Project.php +++ b/src/Utils/Project.php @@ -20,8 +20,8 @@ class Project { protected $dir; - private $errors = array(); - private $info = array(); + private $errors = []; + private $info = []; private static $availableDbRegions = [ // North America 'northamerica-northeast1', @@ -80,7 +80,7 @@ public function downloadArchive($name, $url, $dir='') $dir = $this->getRelativeDir($dir); if (substr($url, -3, 3) === 'zip') { - $zip = new \ZipArchive; + $zip = new \ZipArchive(); if ($zip->open($file) === false) { $this->errors[] = 'Failed to open a zip file: ' . $file; return; @@ -135,7 +135,7 @@ public function getDir() public function getInfo() { $ret = $this->info; - $this->info = array(); + $this->info = []; return $ret; } diff --git a/src/Utils/WordPress/Project.php b/src/Utils/WordPress/Project.php index 4c418e5..4cb3bb1 100644 --- a/src/Utils/WordPress/Project.php +++ b/src/Utils/WordPress/Project.php @@ -19,12 +19,12 @@ use Exception; use Google\Cloud\Utils\Project as BaseProject; +use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; -use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Filesystem\Filesystem; class Project extends BaseProject @@ -41,6 +41,7 @@ class Project extends BaseProject private $input; private $output; private $helper; + private $filesystem; private $wordPressDir; public function __construct(InputInterface $input, OutputInterface $output, QuestionHelper $helper = null) @@ -260,7 +261,7 @@ public function runComposer() private function report() { foreach ($this->getInfo() as $value) { - $this->output->writeln("" . $value . ""); + $this->output->writeln('' . $value . ''); } if ($this->getErrors()) { throw new Exception(implode("\n", $this->getErrors()));