Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW Refactor to not require sake #2

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ it is a requirement of `silverstripe/graphql`.
## Configuration

The plugin runs `sake dev/graphql/build` by default, which builds all schemas.
Set an `SS_GRAPHQL_COMPOSER_CMD` environment constant in order to customise this.
Set an `SS_GRAPHQL_COMPOSER_BUILD_SCHEMAS` environment constant in order to influence this behaviour.
You can either limit this to a specific schema
([details](https://docs.silverstripe.org/en/4/developer_guides/graphql/getting_started/building_the_schema/)),
or set it to an empty string to disable execution.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
},
"require": {
"composer-plugin-api": "^1.1 || ^2",
"silverstripe/graphql": "^4"
"silverstripe/graphql": "^4",
"silverstripe/framework": "^4.9 || 4.x-dev"
},
"require-dev": {
"composer/composer": "^1.2 || 2"
Expand Down
78 changes: 65 additions & 13 deletions src/Plugin.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
<?php

namespace SilverStripe\GraphQLComposerPlugin;

use Composer\Composer;
use Composer\Plugin\PluginInterface;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Script\Event;
use Composer\IO\IOInterface;
use ReflectionClass;
use SilverStripe\Core\CoreKernel;
use SilverStripe\Core\DatabaselessKernel;
use SilverStripe\GraphQL\Schema\Exception\EmptySchemaException;
use SilverStripe\GraphQL\Schema\Schema;
use SilverStripe\GraphQL\Schema\SchemaBuilder;
use SilverStripe\GraphQL\Schema\Storage\CodeGenerationStoreCreator;
use SilverStripe\ORM\Connect\MySQLDatabase;
use SilverStripe\ORM\Connect\NullDatabase;
use SilverStripe\ORM\DB;

class Plugin implements PluginInterface, EventSubscriberInterface
{
Expand All @@ -19,6 +24,11 @@ class Plugin implements PluginInterface, EventSubscriberInterface
*/
protected $io;

/**
* @var Composer
*/
protected $composer;

public static function getSubscribedEvents()
{
return array(
Expand All @@ -30,6 +40,7 @@ public static function getSubscribedEvents()
public function activate(Composer $composer, IOInterface $io)
{
$this->io = $io;
$this->composer = $composer;
}

public function deactivate(Composer $composer, IOInterface $io)
Expand All @@ -44,21 +55,62 @@ public function uninstall(Composer $composer, IOInterface $io)

public function generateSchema(Event $event)
{
$schemas = getenv('SS_GRAPHQL_COMPOSER_BUILD_SCHEMAS');

// vendor/bin is temorarily pushed on top of PATH, see https://getcomposer.org/doc/articles/scripts.md
$cmd = defined('SS_GRAPHQL_COMPOSER_CMD') ? SS_GRAPHQL_COMPOSER_CMD : 'sake dev/graphql/build';

// Allow disabling by null'ing the env var
if (!$cmd) {
// Allow opt-out
if ($schemas === '') {
return;
}

// title() and section() exist in symfony/console, but not through IOInterface
$this->io->write('<info>######################################################</info>');
$this->io->write('<info>silverstripe/graphql-composer-plugin: Building schemas</info>');
$this->io->write('<info>######################################################</info>');
// https://github.com/composer/composer/issues/5998
$vendorDir = $this->composer->getConfig()->get('vendor-dir');
require_once $vendorDir . '/autoload.php';
// Required for BASE_PATH
require_once $vendorDir . '/silverstripe/framework/src/includes/constants.php';

// Throw an exception when any logic in this execution is attempting to perform a query.
// GraphQL code generation can happen on environments which don't have a valid database connection,
// for example in CI when preparing a deployment package.
$db = new NullDatabase();
$db->setQueryErrorMessage('Database query detected during GraphQL code generation: %s');
$db->setErrorMessage('Database activity detected during GraphQL code generation.');
DB::set_conn($db);

$out = shell_exec($cmd);
$this->io->write($out);
// Not using sake because it creates a HTTPApplication through cli-script.php.
// This would trigger middlewares assuming a HTTP request execution
// (rather than CLI), which then connect to the database that might not be available during this build.
$kernel = new DatabaselessKernel(BASE_PATH);

// Not booting error handling since it assumes a (faked) HTTP execution context
// through SilverStripe\Logging\HTTPOutputHandler, and can in some contexts fail
// because HTTP variables aren't defined (see cli-script.php).
$kernel->setBootErrorHandling(false);

try {
// Any composer update can introduce new config statements that require a manifest flush.
// Since there is no way to pass flush=1 through composer commands, the safest way is to always perform the flush.
$kernel->boot(true);

$this->io->write('<info>silverstripe/graphql-composer-plugin: Building schemas</info>');

$keys = $schemas ? explode(',', $schemas) : array_keys(Schema::config()->get('schemas'));
$keys = array_filter($keys, function ($key) {
return $key !== Schema::ALL;
});
foreach ($keys as $key) {
$builder = SchemaBuilder::singleton();
$schema = $builder->boot($key);
$this->io->write(sprintf('Building GraphQL schema "%s"... ', $key), false);
try {
// Not invoking with clean=1 since this would negatively affect runtime of "composer install"
$builder->build($schema, true);
$this->io->write('done.');
} catch (EmptySchemaException $e) {
$this->io->write('schema is empty, skipping.');
}
}
} finally {
$kernel->shutdown();
}
}
}