Skip to content

Commit

Permalink
Merge pull request #12 from christoph-daehne/main
Browse files Browse the repository at this point in the history
FEATURE: connect to existing Prunner system service
  • Loading branch information
skurfuerst committed Nov 14, 2023
2 parents 43cb72b + ff2d09f commit 17bc743
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 20 deletions.
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

0 comments on commit 17bc743

Please sign in to comment.