Skip to content

Commit

Permalink
API Add 'wait' step during publish to wait for package to become avai…
Browse files Browse the repository at this point in the history
…lable before archive
  • Loading branch information
Damian Mooyman committed Oct 6, 2015
1 parent f805e81 commit d42f351
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 5 deletions.
10 changes: 5 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ cow release:publish 3.1.14-rc1 -vvv

## Release

`cow release <version>` will perform all release tasks. <version> is mandatory and must be the exact tag name to release.
`cow release <version>` will perform the first part of the release tasks.
<version> is mandatory and must be the exact tag name to release.

This command has these options:

Expand All @@ -53,8 +54,6 @@ it will install to the path specified by `./release-<version>` in the current di
If omitted, no branching is performed. `--branch-auto` can be used to just default to the major.minor.patch
version of the release. It's advisable to specify this, but not always necessary, when doing pre-releases.

## Release sub-commands

`release` actually has several sub-commands which can be run independently. These are as below:

* `release:create` creates the project folder
Expand All @@ -80,8 +79,6 @@ This command has these options:
* `--aws-profile <profile>` to specify the AWS profile name for uploading releases to s3. Check with
[email protected] if you don't have an AWS key setup.

## Publish sub-commands

The release process, as with the initial `cow release` command, will actually be composed of several sub-commands,
each of which could be run separately.

Expand All @@ -90,6 +87,9 @@ each of which could be run separately.
* `release:archive` Generate tar.gz and zip archives of this release
* `release:upload` Upload archived projects to silverstripe.org

After the push step, `release:publish` will automatically wait for this version to be available in packagist.org
before continuing.

## Module-level commands

Outside of doing core releases, you can use this for specific modules
Expand Down
5 changes: 5 additions & 0 deletions src/Commands/Release/Publish.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\Cow\Steps\Release\PushRelease;
use SilverStripe\Cow\Steps\Release\TagModules;
use SilverStripe\Cow\Steps\Release\UploadArchive;
use SilverStripe\Cow\Steps\Release\Wait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;

Expand Down Expand Up @@ -42,6 +43,10 @@ protected function fire() {
$push = new PushRelease($this, $directory, $modules);
$push->run($this->input, $this->output);

// Once pushed, wait until installable
$wait = new Wait($this, $version);
$wait->run($this->input, $this->output);

// Create packages
$package = new BuildArchive($this, $version, $directory);
$package->run($this->input, $this->output);
Expand Down
108 changes: 108 additions & 0 deletions src/Steps/Release/Wait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace SilverStripe\Cow\Steps\Release;

use Exception;
use SilverStripe\Cow\Model\ReleaseVersion;
use SilverStripe\Cow\Steps\Step;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Creates a new project
*/
class Wait extends Step {

protected $package = 'silverstripe/installer';

protected $stability = 'dev';

/**
* Seconds to timeout error
* Defaults to 15 minutes
*
* @var int
*/
protected $timeout = 5400;

/**
* @var ReleaseVersion
*/
protected $version;

/**
*
* @param Command $command
* @param array $version
* @param type $directory
*/
public function __construct(Command $command, ReleaseVersion $version) {
parent::__construct($command);
$this->version = $version;
}

/**
* Create a new project
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function run(InputInterface $input, OutputInterface $output) {
$version = $this->version->getValue();
$this->log($output, "Waiting for version {$version} to be available via packagist");
$this->waitLoop($output);
$this->log($output, "Version {$version} is now available");
}

protected function waitLoop(OutputInterface $output) {
$start = time();
$version = $this->version->getValue();
while($start + $this->timeout >= time()) {
$versions = $this->getAvailableVersions($output);
if(in_array($version, $versions)) {
return;
}
// Wait
$this->log($output, "Version {$version} not available; checking again in 20 seconds");

// Progress bar for 20 seconds
$progress = new ProgressBar($output, 20);
$progress->start();
for($i = 0; $i < 20; $i++) {
$progress->advance();
sleep(1);
}
$progress->finish();
$output->writeln('');
}

// Timeout
throw new Exception(
"Waiting for version {$version} to be available timed out after " . $this->timeout . " seconds"
);
}

/**
* Determine installable versions composer knows about and can install
*
* @return array
*/
protected function getAvailableVersions(OutputInterface $output) {
$error = "Could not parse available versions from command \"composer show {$this->package}\"";
$output = $this->runCommand($output, array("composer", "show", $this->package), $error);

// Parse output
if($output && preg_match('/^versions\s*:\s*(?<versions>(\S.+\S))\s*$/m', $output, $matches)) {
return preg_split('/\s*,\s*/', $matches['versions']);
}

throw new Exception($error);
}

public function getStepName() {
return 'wait';
}

}

0 comments on commit d42f351

Please sign in to comment.