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
12 changes: 12 additions & 0 deletions Classes/Composer/InstallerScripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ class InstallerScripts

const DEFAULT_VERSION_TO_INSTALL = '1.0.1';

/**
* Downloads the prunner binaries from https://github.com/Flowpack/prunner to ./prunner.
*
* You can pin the prunner version in the composer.json#extra.prunner-version field.
* You can also set it to 'skip-download' to skip the download.
*
* @return void
*/
public static function postUpdateAndInstall()
{
$platform = php_uname('s'); // stuff like Darwin etc
Expand All @@ -58,6 +66,10 @@ public static function postUpdateAndInstall()
$version = $extra['prunner-version'];
$versionMessage = ' (OVERRIDDEN in composer.json)';
}
if ($version === 'skip-download') {
echo '> Not downloading prunner (due to "skip-download" instruction in composer.json)';
return;
}

$baseDirectory = 'prunner';
$platformSpecificTargetDirectory = $baseDirectory . '/' . $platform . '_' . $architecture;
Expand Down
33 changes: 30 additions & 3 deletions Classes/Controller/ProxyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class ProxyController extends \Neos\Flow\Mvc\Controller\ActionController
*/
protected $directory;

/**
* @Flow\InjectConfiguration(path="configFile")
* @var string
*/
protected $configFile;

/**
* @Flow\InjectConfiguration(path="jwtSecret")
* @var string
Expand Down Expand Up @@ -56,9 +62,8 @@ public function indexAction(string $path, string $subpath)
} else {
try {
// Try to parse prunner config to get JWT secret
$config = Yaml::parseFile($this->directory . '/.prunner.yml');
$jwtSecret = $config['jwt_secret'];
} catch (ParseException $e) {
$jwtSecret = $this->loadJwtSecretFromConfigFile();
} catch (\RuntimeException $e) {
$this->response->setContentType('application/json');
$this->response->setStatusCode(500);
return json_encode(['error' => 'Invalid prunner configuration (could not read JWT secret)']);
Expand Down Expand Up @@ -87,4 +92,26 @@ public function indexAction(string $path, string $subpath)

return $response->getBody();
}

/**
* @return string
*/
private function loadJwtSecretFromConfigFile(): string
{
if ($this->configFile && file_exists($this->configFile)) {
$path = $this->configFile;
} elseif ($this->directory && file_exists($this->directory . '/.prunner.yml')) {
$path = $this->directory . '/.prunner.yml';
} else {
throw new \RuntimeException("Failed to locate prunner config file at " . $this->configFile . " or " . $this->directory . '/.prunner.yml');
}
try {
// Try to parse prunner config to get JWT secret
$config = Yaml::parseFile($path);
$jwtSecret = $config['jwt_secret'];
} catch (ParseException $e) {
throw new \RuntimeException('Invalid prunner configuration (could not read JWT secret)');
}
return $jwtSecret;
}
}
2 changes: 1 addition & 1 deletion Classes/Dto/Job.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static function fromJsonArray(array $in): self
}

/**
* @return string
* @return JobId
*/
public function getId(): JobId
{
Expand Down
82 changes: 75 additions & 7 deletions Classes/Dto/Jobs.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/
class Jobs implements \IteratorAggregate
{

/**
* @var Job[]
*/
Expand All @@ -20,7 +21,6 @@ private function __construct(array $jobs)
$this->jobs = $jobs;
}


public static function fromJsonArray(array $in): self
{
$converted = [];
Expand All @@ -42,22 +42,90 @@ public function forPipeline(PipelineName $pipeline): Jobs
return new self($filteredJobs);
}

/**
* @return Jobs all scheduled jobs not yet started
*/
public function waiting(): Jobs
{
return $this->filter(function (Job $job) {
return !$job->getStart();
});
}

/**
* Filter running jobs
*
* @return Jobs
*/
public function running(): Jobs
{
$filteredJobs = [];
foreach ($this->jobs as $job) {
return $this->filter(function (Job $job) {
// running = started jobs which have not finished.
if ($job->getStart() !== null && !$job->getEnd()) {
$filteredJobs[] = $job;
return $job->getStart() !== null && !$job->getEnd();
});
}

/**
* @return Jobs successful, canceled and failed jobs
*/
public function completed(): Jobs
{
return $this->filter(function (Job $job) {
return $job->isCompleted();
});
}

/**
* @return Jobs successfully completed jobs
*/
public function successful(): Jobs
{
return $this->filter(function (Job $job) {
return $job->isCompleted() && !$job->isErrored() && !$job->isCanceled();
});
}

/**
* @return Jobs canceled jobs
*/
public function canceled(): Jobs
{
return $this->filter(function (Job $job) {
return $job->isCanceled();
});
}

/**
* @return Jobs failed jobs
*/
public function errored(): Jobs
{
return $this->filter(function (Job $job) {
return $job->isErrored();
});
}

/**
* @param callable $predicate function(Job $job): bool
* @return Jobs all jobs where $predicate($job)
*/
public function filter(callable $predicate): Jobs
{
$result = [];
foreach ($this->jobs as $job) {
if ($predicate($job)) {
$result[] = $job;
}
}
return new self($result);
}

return new self($filteredJobs);
/**
* @return Job[]
*/
public function getArray(): array
{
return $this->jobs;
}

/**
Expand All @@ -67,4 +135,4 @@ public function getIterator()
{
return new \ArrayIterator($this->jobs);
}
}
}
9 changes: 8 additions & 1 deletion Classes/Dto/Pipelines.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ public static function fromJsonArray(array $in): self
return $pipelines;
}

/**
* @return Pipeline[]
*/
public function getArray(): array
{
return $this->pipelines;
}

/**
* @return \Iterator<Pipeline>
Expand All @@ -32,4 +39,4 @@ public function getIterator()
{
return new \ArrayIterator($this->pipelines);
}
}
}
9 changes: 8 additions & 1 deletion Classes/Dto/TaskResults.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ public function get(string $taskName): ?TaskResult

}

/**
* @return TaskResult[]
*/
public function getArray(): array {
return $this->taskResults;
}

/**
* @return \Iterator<TaskResult>
*/
Expand All @@ -156,4 +163,4 @@ public function allowsCallOfMethod($methodName)
return true;
}

}
}
35 changes: 28 additions & 7 deletions Classes/PrunnerApiService.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class PrunnerApiService
*/
protected $directory;

/**
* @Flow\InjectConfiguration(path="configFile")
* @var string
*/
protected $configFile;

/**
* @Flow\InjectConfiguration(path="jwtSecret")
* @var string
Expand Down Expand Up @@ -103,13 +109,7 @@ public function apiCall(string $method, string $subpath, ?string $body): Respons
if (!empty($this->jwtSecret)) {
$jwtSecret = $this->jwtSecret;
} else {
try {
// Try to parse prunner config to get JWT secret
$config = Yaml::parseFile($this->directory . '/.prunner.yml');
$jwtSecret = $config['jwt_secret'];
} catch (ParseException $e) {
throw new \RuntimeException('Invalid prunner configuration (could not read JWT secret)');
}
$jwtSecret = $this->loadJwtSecretFromConfigFile();
}

// There are usecases where we want to call prunner from the CLI. We don't have an initialized user there, thus we
Expand All @@ -122,4 +122,25 @@ public function apiCall(string $method, string $subpath, ?string $body): Respons
return $client->request($method, $url, ['headers' => ['Authorization' => 'Bearer ' . $authToken], 'body' => $body, 'http_errors' => false]);
}

/**
* @return string
*/
private function loadJwtSecretFromConfigFile(): string
{
if ($this->configFile && file_exists($this->configFile)) {
$path = $this->configFile;
} elseif ($this->directory && file_exists($this->directory . '/.prunner.yml')) {
$path = $this->directory . '/.prunner.yml';
} else {
throw new \RuntimeException("Failed to locate prunner config file at " . $this->configFile . " or " . $this->directory . '/.prunner.yml');
}
try {
// Try to parse prunner config to get JWT secret
$config = Yaml::parseFile($path);
$jwtSecret = $config['jwt_secret'];
} catch (ParseException $e) {
throw new \RuntimeException('Invalid prunner configuration (could not read JWT secret)');
}
return $jwtSecret;
}
}
3 changes: 3 additions & 0 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ Flowpack:
# Base URL to prunner API
apiBaseUrl: 'http://localhost:9009/'
# Working directory of prunner for loading config
# DEPRECATED: use configFile
directory: '%FLOW_PATH_ROOT%'
# Path to the prunner config file to load the JWT secret for authentication
configFile: '%FLOW_PATH_ROOT%/.prunner.yml'
# Explicitly set JWT secret if prunner config is not accessible
jwtSecret: ~

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ will be downloaded. However, it is possible to override this via `extra.prunner-
}
```

## Skip the Prunner binary download

In case you want to install Prunner manually,
you can skip the download of the Prunner entirely
by setting `extra.prunner-version` in the root `composer.json` to `"skip-download"`.

```json
{
"extra": {
"prunner-version": "skip-download"
}
}
```

## Building the UI package

In [prunner-ui](https://github.com/Flowpack/prunner-ui), run `yarn build`
Expand Down