Skip to content
Merged
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
6 changes: 6 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ parameters:
count: 1
path: src/Gitonomy/Git/Repository.php

-
message: '#^Method Gitonomy\\Git\\Repository\:\:runProcess\(\) has parameter \$args with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Gitonomy/Git/Repository.php

-
message: '#^Method Gitonomy\\Git\\Repository\:\:shell\(\) has parameter \$env with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
Expand Down
33 changes: 27 additions & 6 deletions src/Gitonomy/Git/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@ public function setDescription(string $description): static
* This command is a facility command. You can run any command
* directly on git repository.
*
* Note that this only returns the standard output of the process. Some
* git commands (`push`, for instance) write their meaningful output to
* stderr even when they succeed: use {@see runProcess()} instead if you
* need access to it.
*
* @param string $command Git command to run (checkout, branch, tag)
* @param array $args Arguments of git command
*
Expand All @@ -478,6 +483,26 @@ public function setDescription(string $description): static
* @throws RuntimeException Error while executing git command (debug-mode only)
*/
public function run(string $command, array $args = []): ?string
{
$process = $this->runProcess($command, $args);

return $process->isSuccessful() ? $process->getOutput() : null;
}

/**
* Same as {@see run()}, but returns the full, already-run process
* instead of only its standard output on success.
*
* This is useful for commands like `push`, which write their
* meaningful output to stderr even when they succeed, so it can't be
* read through run().
*
* @param string $command Git command to run (checkout, branch, tag)
* @param array $args Arguments of git command
*
* @throws RuntimeException Error while executing git command (debug-mode only)
*/
public function runProcess(string $command, array $args = []): Process
{
$process = $this->getProcess($command, $args);

Expand All @@ -488,13 +513,11 @@ public function run(string $command, array $args = []): ?string

$process->run();

$output = $process->getOutput();

if ($this->logger && $this->debug) {
$duration = microtime(true) - $before;
$this->logger->debug(\sprintf('last command (%s) duration: %sms', $command, \sprintf('%.2f', $duration * 1000)));
$this->logger->debug(\sprintf('last command (%s) return code: %s', $command, $process->getExitCode()));
$this->logger->debug(\sprintf('last command (%s) output: %s', $command, $output));
$this->logger->debug(\sprintf('last command (%s) output: %s', $command, $process->getOutput()));
}

if (!$process->isSuccessful()) {
Expand All @@ -507,11 +530,9 @@ public function run(string $command, array $args = []): ?string
if ($this->debug) {
throw new ProcessException($process);
}

return null;
}

return $output;
return $process;
}

/**
Expand Down
21 changes: 21 additions & 0 deletions tests/Gitonomy/Git/Tests/RepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ public function testRunReturnsNullInsteadOfThrowingWhenDebugIsFalse(): void
$this->assertNull($repository->run('not-a-command'));
}

public function testRunProcessGivesAccessToStderrOnSuccess(): void
{
$repository = self::createFoobarRepository(false);

// `git checkout` reports the switched branch on stderr, even on success.
$process = $repository->runProcess('checkout', ['master']);

$this->assertTrue($process->isSuccessful());
$this->assertStringContainsString('master', $process->getErrorOutput());
}

public function testRunProcessReturnsFailedProcessInsteadOfThrowingWhenDebugIsFalse(): void
{
$repository = self::createFoobarRepository(true);
$repository = new Repository($repository->getPath(), array_merge(self::getOptions(), ['debug' => false]));

$process = $repository->runProcess('not-a-command');

$this->assertFalse($process->isSuccessful());
}

public function testGetShortHashThrowsCleanExceptionWhenDebugIsFalse(): void
{
$repository = self::createFoobarRepository(true);
Expand Down