Skip to content

Commit 1a67012

Browse files
committed
API Update API to reflect changes to CLI interaction
1 parent ef4cbfe commit 1a67012

16 files changed

+158
-243
lines changed

_config/dev.yml

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
11
---
22
Name: graphql-dev
33
---
4-
SilverStripe\ORM\DatabaseAdmin:
4+
SilverStripe\Dev\Command\DbBuild:
55
extensions:
6-
- SilverStripe\GraphQL\Extensions\DevBuildExtension
6+
- SilverStripe\GraphQL\Extensions\DbBuildExtension
77

88
SilverStripe\Dev\DevelopmentAdmin:
9-
registered_controllers:
10-
graphql:
11-
controller: SilverStripe\GraphQL\Dev\DevelopmentAdmin
12-
links:
13-
graphql: 'List GraphQL development tools'
14-
SilverStripe\GraphQL\Dev\DevelopmentAdmin:
15-
registered_controllers:
16-
build:
17-
controller: SilverStripe\GraphQL\Dev\Build
18-
links:
19-
build: Build the GraphQL schema
9+
commands:
10+
'graphql/build': 'SilverStripe\GraphQL\Dev\Build'

_config/logging.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ after: '#logging'
44
---
55

66
SilverStripe\Core\Injector\Injector:
7-
# Omits the HTTPOutputHandler from the logger so errors won't appear in output
7+
# Omits the ErrorOutputHandler from the logger so errors won't appear in output
88
Psr\Log\LoggerInterface.graphql-quiet:
99
type: singleton
1010
class: Monolog\Logger

docs/en/01_getting_started/04_building_the_schema.md

+12-12
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,19 @@ whenever the schema definition changes, or a new schema definition is added.
2222

2323
### What triggers a GraphQL code build?
2424

25-
- Any time you run the `dev/graphql/build` command to explicitly build your GraphQL schemas.
26-
- Any time you run the `dev/build` command on your project.
25+
- Any time you run the `sake graphql:build` command to explicitly build your GraphQL schemas.
26+
- Any time you run the `sake db:build` command on your project.
2727
- `silverstripe/graphql` will attempt to generate your schema "on-demand" on the first GraphQL request *only* if it wasn’t already generated.
2828

2929
> [!WARNING]
3030
> Relying on the "on-demand" schema generation on the first GraphQL request requires some additional consideration.
3131
> See [deploying the schema](06_deploying_the_schema.md#on-demand).
3232
33-
#### Running `dev/graphql/build`
33+
#### Running `sake graphql:build`
3434

35-
The main command for generating the schema code is `dev/graphql/build`.
35+
The main command for generating the schema code is `sake graphql:build`.
3636

37-
`vendor/bin/sake dev/graphql/build`
37+
`vendor/bin/sake graphql:build`
3838

3939
This command takes an optional `schema` parameter. If you only want to generate a specific schema
4040
(e.g. generate your custom schema, but not the CMS schema), you should pass in the name of the
@@ -43,19 +43,19 @@ schema you want to build.
4343
> [!NOTE]
4444
> If you do not provide a `schema` parameter, the command will build all schemas.
4545
46-
`vendor/bin/sake dev/graphql/build schema=default`
46+
`vendor/bin/sake graphql:build --schema=default`
4747

4848
> [!NOTE]
4949
> Most of the time, the name of your custom schema is `default`.
5050
5151
Keep in mind that some of your changes will be in YAML in the `_config/` directory, which also
5252
requires a flush.
5353

54-
`vendor/bin/sake dev/graphql/build schema=default flush=1`
54+
`vendor/bin/sake graphql:build --schema=default --flush`
5555

56-
#### Building on dev/build
56+
#### Building with `sake db:build`
5757

58-
By default, all schemas will be built during `dev/build`. To disable this, change the config:
58+
By default, all schemas will be built during `sake db:build`. To disable this, change the config:
5959

6060
```yml
6161
SilverStripe\GraphQL\Extensions\DevBuildExtension:
@@ -74,11 +74,11 @@ If the type hasn't changed, it doesn't get re-built. This reduces build times to
7474

7575
#### Clearing the schema cache
7676

77-
If you want to completely re-generate your schema from scratch, you can add `clear=1` to the `dev/graphql/build` command.
77+
If you want to completely re-generate your schema from scratch, you can add `--clear` to the `sake graphql:build` command.
7878

79-
`vendor/bin/sake dev/graphql/build schema=default clear=1`
79+
`vendor/bin/sake graphql:build --schema=default --clear`
8080

81-
If your schema is producing unexpected results, try using `clear=1` to eliminate the possibility
81+
If your schema is producing unexpected results, try using `--clear` to eliminate the possibility
8282
of a caching issue. If the issue is resolved, record exactly what you changed and [create an issue](https://github.com/silverstripe/silverstripe-graphql/issues/new).
8383

8484
### Build gotchas

docs/en/01_getting_started/06_deploying_the_schema.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ One way or another, you must get the `.graphql-generated/` and `public/_graphql/
1414

1515
### Single-server hosting solutions with simple deployments {#simple-single-server}
1616

17-
If you host your site on a single server and you always run `dev/build` during the deployment, then assuming you have set up permissions to allow the webserver to write to the `.graphql-generated/` and `public/_graphql/` folders, your GraphQL schema will be built for you as a side-effect of running `dev/build`. You don't need to do anything further. Note that if your schema is exceptionally large you may still want to read through the rest of the options below.
17+
If you host your site on a single server and you always run `sake db:build` during the deployment, then assuming you have set up permissions to allow the webserver to write to the `.graphql-generated/` and `public/_graphql/` folders, your GraphQL schema will be built for you as a side-effect of running `sake db:build`. You don't need to do anything further. Note that if your schema is exceptionally large you may still want to read through the rest of the options below.
1818

1919
### Options for any hosting solution
2020

2121
#### Commit the schema to version control {#commit-to-vcs}
2222

23-
A simplistic approach is to build the schema in your local development environment and add the `.graphql-generated/` and `public/_graphql/` folders to your version control system. With this approach you would most likely want to disable schema generation at `dev/build`.
23+
A simplistic approach is to build the schema in your local development environment and add the `.graphql-generated/` and `public/_graphql/` folders to your version control system. With this approach you would most likely want to disable schema generation with `sake db:build`.
2424

2525
This approach has the advantage of being very simple, but it will pollute your commits with massive diffs for the generated code.
2626

@@ -29,19 +29,19 @@ This approach has the advantage of being very simple, but it will pollute your c
2929
3030
#### Explicitly build the schema during each deployment {#build-during-deployment}
3131

32-
Many projects will automatically run a `dev/build` whenever they deploy a site to their production environment. If that’s your case, then you can just let this process run normally and generate the `.graphql-generated/` and `public/_graphql/` folders for you. This will allow you to add these folders to your `.gitignore` file and avoid tracking the folder in your version control system.
32+
Many projects will automatically run `sake db:build` whenever they deploy a site to their production environment. If that’s your case, then you can just let this process run normally and generate the `.graphql-generated/` and `public/_graphql/` folders for you. This will allow you to add these folders to your `.gitignore` file and avoid tracking the folder in your version control system.
3333

34-
Be aware that for this approach to work, the process executing the `dev/build` must have write access to create the folders (or you must create those folders yourself, and give write access for those folders specifically), and for multi-server environments a `dev/build` or `dev/graphql/build` must be executed on each server hosting your site after each deployment.
34+
Be aware that for this approach to work, the process executing `sake db:build` must have write access to create the folders (or you must create those folders yourself, and give write access for those folders specifically), and for multi-server environments `sake db:build` or `sake graphql:build` must be executed on each server hosting your site after each deployment.
3535

3636
#### Use a CI/CD pipeline to build your schema {#using-ci-cd}
3737

3838
Projects with more sophisticated requirements or bigger schemas exposing more than 100 `DataObject` classes may want to consider using a continuous-integration/continuous-deployment (CI/CD) pipeline to build their GraphQL schema.
3939

40-
In this kind of setup, you would need to update your deployment script to run the `dev/graphql/build` command which builds the `.graphql-generated/` and `public/_graphql/` folders. In multi-server environments this must be executed on each server hosting your site.
40+
In this kind of setup, you would need to update your deployment script to run the `sake graphql:build` command which builds the `.graphql-generated/` and `public/_graphql/` folders. In multi-server environments this must be executed on each server hosting your site.
4141

4242
### Multi-server hosting solutions {#multi-server}
4343

44-
If your site is hosted in an environment with multiple servers or configured to auto-scale with demand, there are some additional considerations. For example if you only generate the schema on one single server (i.e. via `dev/build` or `dev/graphql/build`), then the other servers won’t have a `.graphql-generated/` or `public/_graphql/` folder (or those folders will be empty if you manually created them).
44+
If your site is hosted in an environment with multiple servers or configured to auto-scale with demand, there are some additional considerations. For example if you only generate the schema on one single server (i.e. via `sake db:build` or `sake graphql:build`), then the other servers won’t have a `.graphql-generated/` or `public/_graphql/` folder (or those folders will be empty if you manually created them).
4545

4646
#### Rely on "on-demand" schema generation on the first GraphQL request {#on-demand}
4747

@@ -58,7 +58,7 @@ Our expectation is that on-demand schema generation will be performant for most
5858
5959
#### Build the schema during/before deployment and share it across your servers {#multi-server-shared-dirs}
6060

61-
If you have a particularly large schema, you may want to ensure it is always built before the first GraphQL request. It might make sense for you to sync your `.graphql-generated/` and `public/_graphql/` folders across all your servers using an EFS or similar mechanism. In that case you only need to run `dev/build` or `dev/graphql/build` on the server with the original folder - but bear in mind that this may have a performance impact.
61+
If you have a particularly large schema, you may want to ensure it is always built before the first GraphQL request. It might make sense for you to sync your `.graphql-generated/` and `public/_graphql/` folders across all your servers using an EFS or similar mechanism. In that case you only need to run `sake db:build` or `sake graphql:build` on the server with the original folder - but bear in mind that this may have a performance impact.
6262

6363
### Performance considerations when building the GraphQL schema {#performance-considerations}
6464

@@ -81,7 +81,7 @@ DataObjects in schema | Build time (ms) | Memory use (MB)
8181

8282
The process that is generating these folders must have write permissions to create the folder and to update existing files. If different users are used to generate the folders, then you must make sure that each user retains write access on them.
8383

84-
For example, if you manually run a `dev/build` under a foobar user, the folders will be owned by foobar. If your web server is running under the www-data user and you try to call `dev/graphql/build` in your browser, you might get an error if www-data doesn’t have write access.
84+
For example, if you manually run `sake db:build` under a foobar user, the folders will be owned by foobar. If your web server is running under the www-data user and you try to visit `dev/graphql/build` in your browser, you might get an error if www-data doesn’t have write access.
8585

8686
### Further reading
8787

docs/en/02_working_with_dataobjects/01_adding_dataobjects_to_the_schema.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ The `*` value on `operations` tells the schema to create all available queries a
5656
- `update`
5757
- `delete`
5858

59-
Now that we've changed our schema, we need to build it using the `dev/graphql/build` command:
59+
Now that we've changed our schema, we need to build it using the `graphql:build` command:
6060

61-
`vendor/bin/sake dev/graphql/build schema=default`
61+
`vendor/bin/sake graphql:build --schema=default`
6262

6363
Now we can access our schema on the default GraphQL endpoint, `/graphql`.
6464

docs/en/03_working_with_generic_types/02_building_a_custom_query.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ queries:
6767

6868
Now, we just have to build the schema:
6969

70-
`vendor/bin/sake dev/graphql/build schema=default`
70+
`vendor/bin/sake graphql:build --schema=default`
7171

7272
### Testing the query
7373

docs/en/03_working_with_generic_types/03_resolver_discovery.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ resolvers:
145145

146146
Re-run the schema build, with a flush (because we created a new PHP class), and let's go!
147147

148-
`vendor/bin/sake dev/graphql/build schema=default flush=1`
148+
`vendor/bin/sake graphql:build --schema=default flush=1`
149149

150150
### Field resolvers
151151

docs/en/03_working_with_generic_types/05_adding_pagination.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ can handle the rest. It will return an array including `edges`, `nodes`, and `pa
9696

9797
Rebuild the schema and test it out:
9898

99-
`vendor/bin/sake dev/graphql/build schema=default`
99+
`vendor/bin/sake graphql:build --schema=default`
100100

101101
```graphql
102102
query {

docs/en/03_working_with_generic_types/06_adding_descriptions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ summary: Add descriptions to just about anything in your schema to improve your
1010

1111
One of the great features of a schema-backed API is that it is self-documenting. If you use
1212
the [`silverstripe/graphql-devtools`](https://github.com/silverstripe/silverstripe-graphql-devtools)
13-
module you can see the documentation by navigating to /dev/graphql/ide in your browser anc clicking
13+
module you can see the documentation by navigating to `/dev/graphql/ide` in your browser anc clicking
1414
on "DOCS" on the right.
1515

1616
Many API developers choose to maximise the benefit of this by adding descriptions to some or

docs/en/07_tips_and_tricks.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ to your environment file. The classnames and filenames in the generated code dir
1717

1818
> [!WARNING]
1919
> Take care not to use `DEBUG_SCHEMA=1` as an inline environment variable to your build command, e.g.
20-
> `DEBUG_SCHEMA=1 vendor/bin/sake dev/graphql/build` because any activity that happens at run time, e.g. querying the schema
20+
> `DEBUG_SCHEMA=1 vendor/bin/sake graphql:build` because any activity that happens at run time, e.g. querying the schema
2121
> will fail, since the environment variable is no longer set.
2222
2323
In live mode, full obfuscation kicks in and the filenames become unreadable. You can only determine the type they map

docs/en/08_architecture_diagrams.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The schema is generated during a build step, which generates code generation art
1616

1717
![A high-level view of the GraphQL build process](_images/build_process.png)
1818

19-
- **`/dev/graphql/build`**: This is the command that builds the schema. It also runs as a side effect of `dev/build` as a fallback. It accepts a `schema` parameter if you only want to build one schema.
19+
- **`sake graphql:build`**: This is the command that builds the schema. It also runs as a side effect of `sake db:build` as a fallback. It accepts a `schema` parameter if you only want to build one schema.
2020

2121
- **Schema Factory**: This class is responsible for rebuilding a schema or fetching an existing one (i.e. as cached generated code)
2222

src/Dev/Build.php

+64-36
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
namespace SilverStripe\GraphQL\Dev;
55

66
use Psr\Log\LoggerInterface;
7-
use SilverStripe\Control\Controller;
8-
use SilverStripe\Control\Director;
9-
use SilverStripe\Control\HTTPRequest;
107
use SilverStripe\Core\Injector\Injector;
11-
use SilverStripe\Dev\DebugView;
8+
use SilverStripe\Dev\Command\DevCommand;
9+
use SilverStripe\Dev\DevelopmentAdmin;
10+
use SilverStripe\HybridExecution\HybridOutput;
1211
use SilverStripe\GraphQL\Schema\DataObject\FieldAccessor;
1312
use SilverStripe\GraphQL\Schema\Exception\EmptySchemaException;
1413
use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException;
@@ -18,38 +17,44 @@
1817
use SilverStripe\GraphQL\Schema\SchemaBuilder;
1918
use SilverStripe\GraphQL\Schema\Storage\CodeGenerationStore;
2019
use SilverStripe\ORM\Connect\NullDatabaseException;
20+
use SilverStripe\Security\PermissionProvider;
21+
use Symfony\Component\Console\Command\Command;
22+
use Symfony\Component\Console\Input\InputInterface;
23+
use Symfony\Component\Console\Input\InputOption;
2124

22-
class Build extends Controller
25+
class Build extends DevCommand implements PermissionProvider
2326
{
24-
private static $url_handlers = [
25-
'' => 'build'
26-
];
27+
protected static string $commandName = 'graphql:build';
28+
29+
protected static string $description = 'Build the GraphQL schema(s)';
2730

28-
private static $allowed_actions = [
29-
'build'
31+
private static array $permissions_for_browser_execution = [
32+
'CAN_DEV_GRAPHQL',
3033
];
3134

32-
/**
33-
* @throws SchemaBuilderException
34-
* @throws SchemaNotFoundException
35-
*/
36-
public function build(HTTPRequest $request): void
35+
public function getTitle(): string
3736
{
38-
$isBrowser = !Director::is_cli();
39-
if ($isBrowser) {
40-
$renderer = DebugView::create();
41-
echo $renderer->renderHeader();
42-
echo $renderer->renderInfo("GraphQL Schema Builder", Director::absoluteBaseURL());
43-
echo "<div class=\"build\">";
44-
}
45-
$clear = true;
46-
47-
$this->buildSchema($request->getVar('schema'), $clear);
37+
return 'GraphQL Schema Builder';
38+
}
4839

49-
if ($isBrowser) {
50-
echo "</div>";
51-
echo $renderer->renderFooter();
40+
protected function execute(InputInterface $input, HybridOutput $output): int
41+
{
42+
$originalLogger = Injector::inst()->get(LoggerInterface::class . '.graphql-build');
43+
try {
44+
$logger = Logger::singleton();
45+
$logger->setOutput($output);
46+
Injector::inst()->registerService($logger, LoggerInterface::class . '.graphql-build');
47+
$this->buildSchema($input->getOption('schema'), true, $output);
48+
} finally {
49+
// Restore default logger back to its starting state
50+
Injector::inst()->registerService($originalLogger, LoggerInterface::class . '.graphql-build');
5251
}
52+
return Command::SUCCESS;
53+
}
54+
55+
protected function getHeading(): string
56+
{
57+
return '';
5358
}
5459

5560
/**
@@ -97,15 +102,15 @@ public function buildSchema(string $key = null, bool $clear = true): void
97102
break;
98103
}
99104
}
100-
$logger->warning("
101-
Your schema configuration requires access to the database. This can happen
105+
$logger->warning(
106+
"Your schema configuration requires access to the database. This can happen
102107
when you add fields that require type introspection (i.e. custom getters).
103108
It is recommended that you specify an explicit type when adding custom getters
104-
to your schema.");
109+
to your schema."
110+
);
105111
if ($candidate) {
106112
$logger->warning(sprintf(
107-
"
108-
This most likely happened when you tried to add the field '%s' to '%s'",
113+
"This most likely happened when you tried to add the field '%s' to '%s'",
109114
$candidate['args'][1],
110115
get_class($candidate['args'][0])
111116
));
@@ -114,9 +119,32 @@ public function buildSchema(string $key = null, bool $clear = true): void
114119
throw $e;
115120
}
116121

117-
$logger->info(
118-
Benchmark::end('build-schema-' . $key, 'Built schema in %sms.')
119-
);
122+
$logger->info(Benchmark::end('build-schema-' . $key, 'Built schema in %sms.'));
120123
}
121124
}
125+
126+
public function getOptions(): array
127+
{
128+
return [
129+
new InputOption(
130+
'schema',
131+
null,
132+
InputOption::VALUE_REQUIRED,
133+
'The name of the schema to be built. If not passed, all schemas will be built',
134+
suggestedValues: array_keys(Schema::config()->get('schemas') ?? [])
135+
)
136+
];
137+
}
138+
139+
public function providePermissions(): array
140+
{
141+
return [
142+
'CAN_DEV_GRAPHQL' => [
143+
'name' => _t(__CLASS__ . '.CAN_DEV_GRAPHQL_DESCRIPTION', 'Can view and execute /dev/graphql'),
144+
'help' => _t(__CLASS__ . '.CAN_DEV_GRAPHQL_HELP', 'Can view and execute GraphQL development tools (/dev/graphql).'),
145+
'category' => DevelopmentAdmin::permissionsCategory(),
146+
'sort' => 80
147+
],
148+
];
149+
}
122150
}

0 commit comments

Comments
 (0)