Skip to content

Commit

Permalink
Merge pull request #36 from aaronbauman/extended_support
Browse files Browse the repository at this point in the history
Extend support to arbitrary cli providers
  • Loading branch information
danielbachhuber authored Sep 30, 2019
2 parents 1dcf474 + f57ef12 commit cda49d5
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 54 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Run composer-lock-updater in your CI system for bot-powered `composer.lock` pull

When you run `clu`, it:

1. Clones a given GitHub or GitLab repository to a working `/tmp/` directory.
1. Clones a given git repository to a working `/tmp/` directory.
2. Runs `composer update` within the working directory.
3. Submits a pull request if changes are detected to a tracked `composer.lock` file.

Expand All @@ -27,6 +27,23 @@ composer-lock-updater depends on `composer` and `git` being available on the sys

Both `hub` and `lab` will need to be authenticated with their respective services in order to create the pull/merge requests.

#### Support for other providers
Copy [clu-config.dist.json](clu-config.dist.json) to `$COMPOSER_HOME/clu-config.json` to add support for your git repository provider, or to make adjustments to the pull request commands. For example, to add support for a Bitbucket-Pantheon project using [Terminus Bitbucket Plugin](https://github.com/aaronbauman/terminus-bitbucket-plugin), create the following `clu-config.json`:
```
{
"providers": {
"terminus": {
"provider": "terminus",
"exec": ["terminus"],
"pr_create": "terminus pr-create --title=\"Update Composer dependencies\" --description %s",
"pr_list": "terminus pr-list",
"pr_close": "terminus pr-close %d",
"title_pattern": "%(\\d+)\\s+Update Composer dependencies\\s+clu\\-([0-9-]*)%"
}
}
}
```

## Using

Run composer-lock-updater within an existing GitHub repository with:
Expand Down
14 changes: 8 additions & 6 deletions bin/clu
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ if ( file_exists( $path = __DIR__ . '/../vendor/autoload.php' )

// Simple argv parsing
$optind = null;
$config = \CLU\Checker::get_config();
$opts = getopt('', ['provider::','security-only'], $optind);
if ( isset( $opts['provider'] ) ) {
if ( ! in_array( $opts['provider'], [ 'github', 'gitlab' ], true ) ) {
CLU\Logger::error( "--[provider]=<provider> must be 'github' or 'gitlab'" );
}
$provider = $opts['provider'];
$provider = $opts['provider'];
} else {
$provider = 'github';
}

\CLU\Checker::check_executables( $provider );
if ( empty($config->providers[$provider]) ) {
CLU\Logger::error( "--[provider]=<provider> must be one of: " . implode(', ', array_keys($config->providers)));
}

\CLU\Checker::check_executables( $config->providers[$provider] );

$pos_args = array_slice($argv, $optind);

Expand All @@ -47,5 +49,5 @@ if ( ! $repo_local_working_copy ) {
$repo_local_working_copy = $cloner->cloneRepo( $repo_url );
}

$runner = new CLU\Runner( $repo_url, $provider );
$runner = new CLU\Runner( $repo_url, $config->providers[$provider]);
$runner->start( $repo_local_working_copy, $opts );
21 changes: 21 additions & 0 deletions clu-config.dist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"providers": {
"github": {
"provider": "github",
"exec": ["hub"],
"pr_create": "hub pull-request -m %s",
"pr_list": "hub pr list --format=\",%i %t%n\" --state=open",
"pr_close": "hub api -XPATCH repos/{owner}/{repo}/issues/%d -f state=closed",
"title_pattern": "%#([\\d]+) Update Composer dependencies \\(([0-9-]*)\\)%"
},
"gitlab": {
"provider": "gitlab",
"exec": ["lab"],
"pr_create": "lab mr create -m %s",
"pr_list": "lab mr list",
"pr_close": "lab mr close %d",
"request_type": "merge request",
"title_pattern": "%#([\\d]+) Update Composer dependencies \\(([0-9-]*)\\)%"
}
}
}
27 changes: 19 additions & 8 deletions src/Checker.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,12 @@ class Checker {
/**
* Check that Git, Composer, and Hub or Lab are available on the filesystem.
*/
public static function check_executables( $provider ) {
$execs = [
public static function check_executables( \stdClass $provider ) {
$execs = array_merge([
'git',
'composer',
'tee',
];
if ( 'github' === $provider ) {
$execs[] = 'hub';
} elseif ( 'gitlab' === $provider ) {
$execs[] = 'lab';
}
], $provider->exec);
foreach( $execs as $exec ) {
exec( 'type ' . escapeshellarg( $exec ), $_, $return_code );
if ( 0 !== $return_code ) {
Expand All @@ -27,4 +22,20 @@ public static function check_executables( $provider ) {
Logger::info( 'Found required executables on system: ' . implode( ', ', $execs ) );
}

public static function get_config() {
$defaults = json_decode(file_get_contents(__DIR__ . '/../clu-config.dist.json'));
$defaults->providers = get_object_vars($defaults->providers);
if (file_exists($path = getenv('COMPOSER_HOME') . '/clu-config.json')
|| file_exists($path = getcwd() . '/clu-config.json')
){
$config = json_decode(file_get_contents($path));
if ($error = json_last_error()) {
return $defaults;
}
if (!empty($config->providers)) {
$defaults->providers = array_merge($defaults->providers, get_object_vars($config->providers));
}
}
return $defaults;
}
}
46 changes: 7 additions & 39 deletions src/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ class Runner {
* Instantiate the runner.
*
* @param string $repo_url
* @param string $provider
* @param \stdClass $provider
*/
public function __construct( $repo_url, $provider ) {
public function __construct( $repo_url, \stdClass $provider ) {
$this->repo_url = $repo_url;
$this->provider = $provider;
}
Expand Down Expand Up @@ -128,11 +128,7 @@ public function start( $target_dir, $opts ) {
Logger::error( 'Failed to push changes to origin.' );
}

if ( $this->isGitHub() ) {
$cmd = 'hub pull-request -m ' . escapeshellarg( $message );
} elseif ( $this->isGitLab() ) {
$cmd = 'lab mr create -m ' . escapeshellarg( $message );
}
$cmd = sprintf($this->provider->pr_create, escapeshellarg( $message ));
Logger::info( $cmd );
passthru( $cmd, $return_code );
if ( 0 !== $return_code ) {
Expand All @@ -149,19 +145,13 @@ public function start( $target_dir, $opts ) {
* @return mixed
*/
private function checkExistingPRBranch( $type ) {
if ( $this->isGitHub() ) {
$cmd = 'hub pr list --format="%i %t%n" --state=open';
} elseif ( $this->isGitLab() ) {
$cmd = 'lab mr list';
} else {
return false;
}
$cmd = $this->provider->pr_list;
exec($cmd, $output_lines, $return_code);
if ( 0 !== $return_code ) {
Logger::error( sprintf( 'Unable to check for existing %ss', $this->getRequestType() ) );
}
foreach ($output_lines as $line) {
if (preg_match('%#([\d]+) Update Composer dependencies \(([0-9-]*)\)%', $line, $matches)) {
if (preg_match($this->provider->title_pattern, $line, $matches)) {
if ( 'number' === $type ) {
return $matches[1];
} elseif ( 'branch' === $type ) {
Expand All @@ -184,11 +174,7 @@ private function closeExistingPRBranch( $branch_name ) {
if ( ! $number ) {
Logger::error( sprintf( 'Unable to find existing %s number', $this->getRequestType() ) );
}
if ( $this->isGitHub() ) {
$cmd = sprintf( 'hub api -XPATCH repos/{owner}/{repo}/issues/%d -f state=closed', $number );
} elseif ( $this->isGitLab() ) {
$cmd = sprintf( 'lab mr close %d', $number );
}
$cmd = sprintf( $this->provider->pr_close, $number );
exec($cmd, $output_lines, $return_code);
if ( 0 !== $return_code ) {
Logger::error( sprintf( 'Unable to close existing %s #%d: %s', $this->getRequestType(), $number, implode( PHP_EOL, $output_lines ) ) );
Expand Down Expand Up @@ -221,31 +207,13 @@ protected function checkSensiolabsSecurity($composerLockPath, &$security_status)
return "\n\n" . implode("\n", $output);
}

/**
* Whether or not the current provider is GitHub.
*
* @return boolean
*/
private function isGitHub() {
return 'github' === $this->provider;
}

/**
* Whether or not the current provider is GitLab.
*
* @return boolean
*/
private function isGitLab() {
return 'gitlab' === $this->provider;
}

/**
* Returns 'pull request' or 'merge request', depending on provider.
*
* @return string
*/
private function getRequestType() {
return $this->isGitLab() ? 'merge request' : 'pull request';
return isset($this->provider->request_type) ? $this->provider->request_type : 'pull request';
}

/**
Expand Down

0 comments on commit cda49d5

Please sign in to comment.