diff --git a/.github/workflows/run-validation.yml b/.github/workflows/run-validation.yml index 54951fe..56cd17e 100644 --- a/.github/workflows/run-validation.yml +++ b/.github/workflows/run-validation.yml @@ -22,6 +22,11 @@ jobs: # https://github.com/shivammathur/setup-php?tab=readme-ov-file#disable-coverage coverage: none + - name: Extract branch name + shell: bash + run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT + id: extract_branch + - name: Get composer cache directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT @@ -48,20 +53,23 @@ jobs: run: | # Initialize status variables to 0 status1=0 - status2=0 - status3=0 - # Run all commands and capture their exit statuses - vendor/bin/robo validate:branch-name || status1=$? || status1=0 - vendor/bin/robo validate:composer-lock || status3=$? || status3=0 - vendor/bin/robo validate:coding-standards || status2=$? || status2=0 + ROBO_VALIDATE_BRANCH_NAME=${{ steps.extract_branch.outputs.branch }} vendor/bin/robo validate:all non_pr - # Exit with a non-zero status if any command failed - if [ "$status1" -ne 0 ] || [ "$status2" -ne 0 ] || [ "$status3" -ne 0 ]; then + # Exit with a non-zero status if the command failed + if [ "$status1" -ne 0 ]; then exit 1 fi - name: Validate pull requests if: github.event_name == 'pull_request' run: | - vendor/bin/robo validate:commit-messages --target-branch="${{ github.base_ref }}" --current-branch="${{ github.head_ref }}" + # Initialize status variables to 0 + status1=0 + + ROBO_VALIDATE_TARGET_BRANCH="${{ github.base_ref }}" ROBO_VALIDATE_CURRENT_BRANCH="${{ github.head_ref }}" vendor/bin/robo validate:all only_pr + + # Exit with a non-zero status if the command failed + if [ "$status1" -ne 0 ]; then + exit 1 + fi diff --git a/robo.example.yml b/robo.example.yml index 5ac1220..539d9e3 100644 --- a/robo.example.yml +++ b/robo.example.yml @@ -11,6 +11,16 @@ command: # XYZ. # This value can be anything you want, as long as it is consistent. project-id: '' + # Used in 'validate:all' + all: + options: + # These are all the robo commands that will be run when validate:all is called. + commands: + - {robo_command: 'validate:coding-standards', label: 'Coding Standards'} + - {robo_command: 'validate:composer-lock', label: 'Composer Lock File'} + - {robo_command: 'validate:commit-messages', label: 'Commit Messages', only_pr: 1} + - {robo_command: 'validate:branch-name', label: 'Branch Name'} + # Used in 'validate:coding-standards' # Requires https://github.com/squizlabs/PHP_CodeSniffer be installed. coding-standards: diff --git a/src/Robo/Plugin/Commands/ValidateCommands.php b/src/Robo/Plugin/Commands/ValidateCommands.php index df04c37..d410887 100644 --- a/src/Robo/Plugin/Commands/ValidateCommands.php +++ b/src/Robo/Plugin/Commands/ValidateCommands.php @@ -50,6 +50,10 @@ protected function isGitRepo(): bool */ protected function getGitBranch(): ?string { + $branch_name = getenv('ROBO_VALIDATE_BRANCH_NAME') ?: ''; + if (strlen($branch_name)) { + return $branch_name; + } if (!$this->isGitRepo()) { $this->printError( 'The current directory is not a git repo, cannot retrieve branch name' @@ -126,9 +130,40 @@ protected function getOptions( * Run all validations. * * @command validate:all + * + * @arg string $run_type The default of 'all' will cause every defined command to run. + * 'only_pr' will run commands that have 'only_pr' set to 1. + * 'non_pr' will run commands that don't have 'only_pr' set to 1. + * + * @option none Will cause no validations to run if 1. + * @option commands An array of array with keys robo_command, label, and + * only_pr. + * + * @return \Robo\ResultData */ - public function validateAll(): ResultData - { + public function validateAll( + string $run_type = 'all', + array $opts = [ + 'none' => 0, + 'commands' => [ + ['robo_command' => 'validate:coding-standards', 'label' => 'Coding Standards'], + ['robo_command' => 'validate:composer-lock', 'label' => 'Composer Lock File'], + ['robo_command' => 'validate:commit-messages', 'label' => 'Commit Messages', 'only_pr' => 1], + ['robo_command' => 'validate:branch-name', 'label' => 'Branch Name'], + ], + ] + ): ResultData { + [ + $none, + $commands, + ] = $this->getOptions([ + 'none', + 'commands', + ], $opts, false); + if ($none) { + $this->sayWithWrapper('Skipping validate:all as configured.'); + return new ResultData(); + } $table = new Table($this->output()); $table ->setHeaders( @@ -138,30 +173,26 @@ public function validateAll(): ResultData 'Command (use this to diagnose individual tests without running all)', ] ); - $output_data[] = [ - 'Coding Standards', - $this->runRoboCommand('validate:coding-standards')->wasSuccessful( - ) ? 'Yes' : 'No', - 'validate:coding-standards', - ]; - $output_data[] = [ - 'Composer Lock File', - $this->runRoboCommand('validate:composer-lock')->wasSuccessful( - ) ? 'Yes' : 'No', - 'validate:composer-lock', - ]; - $output_data[] = [ - 'Commit Messages', - $this->runRoboCommand('validate:commit-messages')->wasSuccessful( - ) ? 'Yes' : 'No', - "validate:commit-messages", - ]; - $output_data[] = [ - 'Branch Name', - $this->runRoboCommand('validate:branch-name')->wasSuccessful( - ) ? 'Yes' : 'No', - "validate:branch-name", - ]; + foreach ($commands as $command) { + // If one only wants to run commands that are good for PR. + if ($run_type === 'only_pr' && !($command['only_pr'] ?? 0)) { + continue; + // If one only wants to run commands that are not good for PR. + } elseif ($run_type === 'non_pr' && ($command['only_pr'] ?? 0)) { + continue; + } + if (empty($command['label']) || empty($command['robo_command'])) { + throw new \Exception('Every item in the namespace command:validate:all:commands must have' . + ' both a robo_command AND label to run. See robo.example.yml for examples.'); + } + $output_data[] = [ + $command['label'], + $this->runRoboCommand($command['robo_command'])->wasSuccessful( + ) ? 'Yes' : 'No', + $command['robo_command'], + ]; + } + $table->setRows($output_data); $success = true; foreach ($output_data as $datum) { @@ -442,6 +473,9 @@ public function validateCommitMessages( $subject ); }; + if (getenv('ROBO_VALIDATE_TARGET_BRANCH') !== false) { + $target_branch = getenv('ROBO_VALIDATE_TARGET_BRANCH'); + } $this->sayWithWrapper( "Validating commit messages to be added to '$target_branch'" ); @@ -453,6 +487,9 @@ public function validateCommitMessages( return new ResultData(ResultData::EXITCODE_ERROR); } + if (getenv('ROBO_VALIDATE_CURRENT_BRANCH') !== false) { + $current_branch = getenv('ROBO_VALIDATE_CURRENT_BRANCH'); + } // If the current branch is not using what's checked out, then fetch the latest from // that branch as a local branch. if ($current_branch !== 'HEAD') { @@ -504,8 +541,9 @@ public function validateCommitMessages( * * @command validate:branch-name * - * @arg string $branch_name The branch name to validate. If not given it - * the current branch will attempt to be detected. + * @arg string $branch_name The branch name to validate. If not given, the + * environment variable ROBO_VALIDATE_BRANCH_NAME will be checked first, + * then current branch will attempt to be detected via git commands. * * @option string $project-id Used as a token replacement in $pattern. * Defaults to ''.