Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Pre push #1137

Open
wants to merge 11 commits into
base: v2.x
Choose a base branch
from
2 changes: 2 additions & 0 deletions grumphp.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ grumphp:
testsuites:
git_pre_commit:
tasks: [phpcs, phpspec, phpunit, composer, composer_normalize, yamllint, phplint, phpparser, psalm]
git_pre_push:
tasks: [phpcs, phpspec, phpunit, composer, composer_normalize, yamllint, phplint, phpparser, psalm]
# On CI, we run paratest separately. For some reason this currently fails in GitHub actions.
ci:
tasks: [phpcs, phpspec, phpunit, composer, composer_normalize, yamllint, phplint, phpparser, psalm]
Expand Down
8 changes: 8 additions & 0 deletions resources/config/console.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ services:
- '@GrumPHP\IO\IOInterface'
tags:
- { name: 'console.command' }
GrumPHP\Console\Command\Git\PrePushCommand:
arguments:
- '@GrumPHP\Collection\TestSuiteCollection'
- '@GrumPHP\Runner\TaskRunner'
- '@GrumPHP\Git\GitRepository'
- '@GrumPHP\Locator\RegisteredFiles'
tags:
- { name: 'console.command' }

# This one is loaded through the TestSuiteCompilerPass
GrumPHP\Collection\TestSuiteCollection:
Expand Down
13 changes: 13 additions & 0 deletions resources/hooks/local/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

#
# Run the hook command.
# Note: this will be replaced by the real command during copy.
#

# Grumphp env vars
$(ENV)
export GRUMPHP_GIT_WORKING_DIR="$(git rev-parse --show-toplevel)"

# Run GrumPHP
cd "${HOOK_EXEC_PATH}" && $(EXEC_GRUMPHP_COMMAND) $(HOOK_COMMAND) --skip-success-output
1 change: 1 addition & 0 deletions spec/Task/Config/MetadataSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function it_contains_an_options_resolver_with_default(): void
'enabled' => true,
'task' => '',
'label' => '',
'git_stage' => ['pre-commit', 'pre-push'],
]);
}

Expand Down
1 change: 1 addition & 0 deletions src/Console/Command/Git/DeInitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class DeInitCommand extends Command
*/
protected static $hooks = [
'pre-commit',
'pre-push',
'commit-msg',
];

Expand Down
1 change: 1 addition & 0 deletions src/Console/Command/Git/InitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class InitCommand extends Command
*/
public static $hooks = [
'pre-commit',
'pre-push',
'commit-msg',
];

Expand Down
106 changes: 106 additions & 0 deletions src/Console/Command/Git/PrePushCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace GrumPHP\Console\Command\Git;

use GrumPHP\Collection\FilesCollection;
use GrumPHP\Collection\TestSuiteCollection;
use GrumPHP\Git\GitRepository;
use GrumPHP\Locator\RegisteredFiles;
use GrumPHP\Runner\TaskRunner;
use GrumPHP\Runner\TaskRunnerContext;
use GrumPHP\Task\Context\GitPrePushContext;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* This command runs the git pre-push hook.
*/
class PrePushCommand extends Command
{
const COMMAND_NAME = 'git:pre-push';
const EXIT_CODE_OK = 0;
const EXIT_CODE_NOK = 1;
const SHA1_EMPTY = '0000000000000000000000000000000000000000';

public function __construct(
private readonly TestSuiteCollection $testSuites,
private readonly TaskRunner $taskRunner,
private readonly GitRepository $repository,
private readonly RegisteredFiles $registeredFilesLocator,
) {
parent::__construct();
}

public static function getDefaultName(): string
{
return self::COMMAND_NAME;
}

protected function configure(): void
{
$this->setDescription('Executed by the pre-push hook');
$this->addOption(
'skip-success-output',
null,
InputOption::VALUE_NONE,
'Skips the success output. This will be shown by another command in the git commit hook chain.'
);
}

public function execute(InputInterface $input, OutputInterface $output): int
{
$files = $this->getChangedFiles();
if ($files === null) {
return self::EXIT_CODE_OK;
}

$context = (
new TaskRunnerContext(
new GitPrePushContext($files),
$this->testSuites->getOptional('git_pre_push')
)
)->withSkippedSuccessOutput((bool) $input->getOption('skip-success-output'));

$output->writeln('<fg=yellow>GrumPHP detected a pre-push command.</fg=yellow>');

$results = $this->taskRunner->run($context);

return $results->isFailed() ? self::EXIT_CODE_NOK : self::EXIT_CODE_OK;
}

protected function getChangedFiles(): ?FilesCollection
{
$fileCollection = new FilesCollection([]);

// Loop over the commits.
while ($commit = trim((string) fgets(STDIN))) {
[$localRef, $localSha, , $remoteSha] = explode(' ', $commit);

if ($localRef === '(delete)' || $localSha === self::SHA1_EMPTY) {
// A branch has been deleted or there's no local branch.
return null;
}

if ($remoteSha === self::SHA1_EMPTY) {
// Do a full check if this is a new branch.
return $this->registeredFilesLocator->locate();
}

$args = ['--no-commit-id', '--name-only', '-r', $localSha, $remoteSha];
$command = (string) $this->repository->run('diff-tree', $args);

foreach (explode("\n", $command) as $file) {
// Avoid empty lines, missing files, and duplicates.
if (!empty($file) && file_exists($file) && !$fileCollection->containsKey($file)) {
$fileCollection->set($file, new \SplFileInfo($file));
}
}
}

return $fileCollection;
}
}
2 changes: 2 additions & 0 deletions src/Task/AbstractExternalTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
abstract class AbstractExternalTask implements TaskInterface
{
use GitContextTrait;

/**
* @var TaskConfigInterface
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Task/AbstractLinterTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
abstract class AbstractLinterTask implements TaskInterface
{
use GitContextTrait;

/**
* @var TaskConfigInterface
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Task/AbstractParserTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
abstract class AbstractParserTask implements TaskInterface
{
use GitContextTrait;

/**
* @var TaskConfigInterface
*/
Expand Down
3 changes: 1 addition & 2 deletions src/Task/Ant.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand All @@ -36,7 +35,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver

public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

public function run(ContextInterface $context): TaskResultInterface
Expand Down
3 changes: 1 addition & 2 deletions src/Task/Atoum.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -47,7 +46,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Task/Behat.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -43,7 +42,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Task/Brunch.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -43,7 +42,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/Task/CloverCoverage.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use GrumPHP\Task\Config\EmptyTaskConfig;
use GrumPHP\Task\Config\TaskConfigInterface;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use GrumPHP\Util\Filesystem;
use SimpleXMLElement;
Expand All @@ -19,6 +18,8 @@

class CloverCoverage implements TaskInterface
{
use GitContextTrait;

/**
* @var Filesystem
*/
Expand Down Expand Up @@ -72,7 +73,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Task/Codeception.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -45,7 +44,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Task/Composer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use GrumPHP\Util\Filesystem;
use Symfony\Component\OptionsResolver\OptionsResolver;
Expand Down Expand Up @@ -61,7 +60,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver

public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

public function run(ContextInterface $context): TaskResultInterface
Expand Down
3 changes: 1 addition & 2 deletions src/Task/ComposerNormalize.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Process\Process;
Expand All @@ -20,7 +19,7 @@ class ComposerNormalize extends AbstractExternalTask
{
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

public static function getConfigurableOptions(): ConfigOptionsResolver
Expand Down
3 changes: 1 addition & 2 deletions src/Task/ComposerRequireChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -41,7 +40,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Task/ComposerScript.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\Config\ConfigOptionsResolver;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -39,7 +38,7 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
*/
public function canRunInContext(ContextInterface $context): bool
{
return $context instanceof GitPreCommitContext || $context instanceof RunContext;
return $this->isGitContextAllowed($context) || $context instanceof RunContext;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/Task/Config/Metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public static function getConfigurableOptions(): \GrumPHP\Task\Config\ConfigOpti
'enabled' => true,
'task' => '',
'label' => '',
'git_stage' => ['pre-commit', 'pre-push'],
]);
}

Expand Down Expand Up @@ -60,6 +61,11 @@ public function label(): string
return (string) $this->metadata['label'];
}

public function gitStages(): array
{
return $this->metadata['git_stage'];
}

public function toArray(): array
{
return $this->metadata;
Expand Down
Loading