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

Adds CLI flags to dev build and start to change what is built and run #8046

Merged
merged 26 commits into from
Feb 13, 2023
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
5 changes: 5 additions & 0 deletions .changeset/plenty-hairs-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-6/core': major
---

Adds additional flags to the `keystone dev`, `keystone build` and `keystone start` CLI commands
5 changes: 3 additions & 2 deletions docs/components/docs/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,9 @@ export function DocsNavigation() {
<NavItem href="/docs/guides/overview">Overview</NavItem>
<NavItem href="/docs/guides/cli">Command Line</NavItem>
<NavItem href="/docs/guides/relationships">Relationships</NavItem>
<NavItem href="/docs/guides/choosing-a-database">
Choosing a Database <Badge look="success">New</Badge>
<NavItem href="/docs/guides/choosing-a-database">Choosing a Database</NavItem>
<NavItem href="/docs/guides/database-migration">
Database Migration <Badge look="success">New</Badge>
</NavItem>
<NavItem href="/docs/guides/filters">
Query Filters <Badge look="success">Updated</Badge>
Expand Down
3 changes: 1 addition & 2 deletions docs/pages/blog/mysql-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authorHandle: "https://twitter.com/flexdinesh"
metaImageUrl: ""
---

We've added support for MySQL to Keystone's list of database providers, bringing the total number of supported database types to three.
We've added support for MySQL to Keystone's list of database providers, bringing the total number of supported database types to three.

Here's an example `db.config` to work with MySQL database.

Expand All @@ -16,7 +16,6 @@ export default config({
db: {
provider: 'mysql',
url: 'mysql://dbuser:dbpass@localhost:5432/keystone',
useMigrations: true,
idField: { kind: 'uuid' },
},
...
Expand Down
4 changes: 0 additions & 4 deletions docs/pages/docs/config/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ These database types are powered by their corresponding Prisma database provider
- `url`: The connection URL for your database
- `onConnect`: which takes a [`KeystoneContext`](../context/overview) object, and lets perform any actions you might need at startup, such as data seeding
- `enableLogging` (default: `false`): Enable logging from the Prisma client.
- `useMigrations` (default: `false`): Determines whether to use migrations or automatically force-update the database with the latest schema and potentially lose data.
- `idField` (default: `{ kind: "cuid" }`): The kind of id field to use, it can be one of: `cuid`, `uuid` or `autoincrement`.
This can also be customised at the list level `db.idField`.
If you are using `autoincrement`, you can also specify `type: 'BigInt'` on PostgreSQL and MySQL to use BigInts.
Expand All @@ -82,7 +81,6 @@ export default config({
onConnect: async context => { /* ... */ },
// Optional advanced configuration
enableLogging: true,
useMigrations: true,
idField: { kind: 'uuid' },
shadowDatabaseUrl: 'postgres://dbuser:dbpass@localhost:5432/shadowdb'
},
Expand All @@ -100,7 +98,6 @@ export default config({
onConnect: async context => { /* ... */ },
// Optional advanced configuration
enableLogging: true,
useMigrations: true,
idField: { kind: 'uuid' },
},
/* ... */
Expand All @@ -117,7 +114,6 @@ export default config({
onConnect: async context => { /* ... */ },
// Optional advanced configuration
enableLogging: true,
useMigrations: true,
idField: { kind: 'uuid' },
},
/* ... */
Expand Down
95 changes: 87 additions & 8 deletions docs/pages/docs/guides/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,36 @@ $ keystone [command]

Commands
dev start the project in development mode (default)
postinstall generate client APIs and types (optional)
build build the project (must be done before using start)
start start the project in production mode
postinstall build the project (for development, optional)
build build the project (required by \`keystone start\`)
start start the project
prisma run Prisma CLI commands safely
telemetry sets telemetry preference (enable/disable/status)
{% if $nextRelease %}

Options
--fix (postinstall) @deprecated
do build the graphql or prisma schemas, don't validate them

--frozen (build)
don't build the graphql or prisma schemas, only validate them

--no-db-push (dev)
don't push any updates of your Prisma schema to your database

--no-prisma (build, dev)
don't build or validate the prisma schema

--no-server (dev)
don't start the express server

--no-ui (build, dev, start)
don't build and serve the AdminUI

--with-migrations (start)
trigger prisma to run migrations as part of startup
{% /if %}

```

{% hint kind="tip" %}
Expand All @@ -31,16 +57,24 @@ We recommend adding the following scripts to your project's `package.json` file:
```json
{
"scripts": {
{% if $nextRelease %}
"build": "keystone build",
"dev": "keystone dev",
"postinstall": "keystone postinstall",
"generate": "keystone prisma migrate dev",
"start": "keystone start --with-migrations",
{% else / %}
"deploy": "keystone build && keystone prisma migrate deploy",
"dev": "keystone dev",
"postinstall": "keystone postinstall",
"start": "keystone start"
{% /if %}
}
}
```

{% hint kind="tip" %}
Note: the deploy script above assumes you are using migrations
Note: Depending on where you are deploying the `prisma migrate deploy` step might be better in the `build` or as a separate step altogether.
{% /hint %}

Read on below for more details about each command, and see [bringing it all together](#bringing-it-all-together) for more details (including some important caveats) about how that "deploy" command works.
Expand All @@ -57,12 +91,28 @@ This is the command you use to start Keystone for local development. It will:
- Generate and apply database migrations based on your Keystone Schema
- Start the local dev server, which hosts the GraphQL API and Admin UI

{% hint kind="warn" %}
Keystone does not currently watch your local files for changes. If you update the config, schema or any other files in your keystone project you'll need to restart the server.
{% /hint %}
{% if $nextRelease %}
### dev flags

- `--no-db-push` - Don't push any updates of your Prisma schema to your database
- `--no-prisma` - Don't build or validate the prisma schema
- `--no-server` - Don't start the express server, will still watch for changes and update the Admin UI and schema files
- `--no-ui` - Don't build and serve the AdminUI
{% /if %}

### About database migrations

{% if $nextRelease %}
When using `keystone dev` the default behaviour is for Keystone to update your database to match your schema using Prisma Migrate. This behaviour is great for the rapid iteration of a schema, but can be modified in the following ways:

- Running `keystone dev --no-db-push` - This will skip the dev migration step and not perform any checks on your database to ensure it matches your schema. This can be useful if you have an existing database or want to handle all migrations yourself. Be aware that this may lead to GraphQL runtime errors if a table or table column is unavailable.

See [`prisma` command](#prisma) below for more information on database migrations.

{% hint kind="tip" %}
Be careful of running `keystone dev` while pointing to a production database as this can cause data loss.
{% /hint %}
{% else /%}
In development, Keystone will migrate the structure of your database for you in one of two ways depending on how you have configured `db.useMigrations`:

- If `db.useMigrations` is `false` (the default), Keystone will use Prisma Migrate to update your database so that it matches your schema. It may lose data while updating your database so you should only use this mode in initial development.
Expand All @@ -75,6 +125,7 @@ Commit the migration files to source control, then when you are hosting your app
{% hint kind="tip" %}
We strongly recommend enabling migrations if you are going to run your app in production. Not doing so risks data loss.
{% /hint %}
{% /if %}

### Resetting the database

Expand All @@ -95,6 +146,11 @@ This is mainly useful early in a project's development lifecycle, when you want
```bash
$ keystone postinstall
```
{% if $nextRelease %}
{% hint kind="tip" %}
Note: `postinstall` is an alias for `keystone build --no-ui --frozen` we recommend switching to this `build` command
{% /hint %}
{% /if %}

Keystone generates several files that your app may depend on, including the Node.js API and TypeScript definitions.

Expand All @@ -109,6 +165,11 @@ While the recommended way to fix this problem is to start your app using `keysto
```bash
$ keystone postinstall --fix
```
{% if $nextRelease %}
{% hint kind="tip" %}
Note: `postinstall --fix` is an alias for `keystone build --no-ui` we recommend switching to this `build` command
{% /hint %}
{% /if %}

## build

Expand All @@ -118,7 +179,14 @@ $ keystone build

This command generates the files needed for Keystone to start in **production** mode. You should run it during the build phase of your production deployment.

It will also validate that the generated files you should have committed to source control are in sync with your Keystone Schema (see `postinstall` above).
It will also validate that the generated files you should have committed to source control are in sync with your Keystone Schema.
{% if $nextRelease %}

### build flags
- `--frozen` - Don't update the graphql or prisma schemas, only validate them, exits with error if the schemas don't match what keystone would generate.
- `--no-prisma` - Don't build or validate the prisma schema
- `--no-ui` - Don't build the AdminUI
{% /if %}

## start

Expand All @@ -129,6 +197,12 @@ $ keystone start
This command starts Keystone in **production** mode. It requires a build to have been generated (see `build` above).

It will not generate or apply any database migrations - these should be run during the **build** or **release** phase of your production deployment.
{% if $nextRelease %}

### start flags
- `--with-migrations` - Trigger prisma to run migrations as part of startup
- `--no-ui` - Don't serve the AdminUI
{% /if %}

## prisma

Expand Down Expand Up @@ -191,6 +265,11 @@ Start Keystone in production mode:
```bash
yarn keystone start
```
{% if $nextRelease %}
{% hint kind="tip" %}
Note: To run migrations before you start Keystone use `keystone start --with-migrations`
{% /hint %}
{% /if %}

#### Notes

Expand Down
52 changes: 52 additions & 0 deletions docs/pages/docs/guides/database-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: "Database Migration"
description: "Learn how to get your production database ready using Keystone's migration"
---

Before running `keystone start` with a production database, you will first need to ensure the database has all the tables and fields that keystone requires. To make this easier keystone can generate the required migration files to store alongside your code, and then run these migrations against your production database.

## Prisma Migrate

Keystone uses Prisma's built-in migration feature, this works by generating `.sql` files into a `./migrations` at the root of your project (ie beside your `keystone.ts` file) and then running those migration files against your production database. For detailed information on how Prisma Migrate works see the [Prisma Migrate docs](https://www.prisma.io/docs/concepts/components/prisma-migrate).

## Running `keystone dev`

By default running `keystone dev` will force push your schema to the database set using `db.url` in your `keystone.ts` file.

{% if $nextRelease %}
## Skipping dev DB push

If you want to look after all migrations, including in dev, yourself you can run `keystone dev --no-db-push` this will not perform the default force push in dev leaving you to perform migrations as you like.

{% hint kind="tip" %}
Running `keystone dev --no-db-push` will return GraphQL runtime errors if tables and/or columns that Keystone requires are not present in the database.
{% /hint %}

## Keystone Prisma Migrate CLI

Keystone offers the following three commonly used commands through Prisma to help manage your migrations.
- `keystone prisma migrate generate` - Generates the migration files to run to set up your production database - these files should be committed to source control and accessible by the `deploy` step. This command is helpful if you want to either leave `keystone dev` as the default behaviour for rapid schema iteration and generate the migrations once you are ready to submit a PR.
- `keystone prisma migrate deploy` - Runs the generated migrations - this command can only be run after a `build` step, and is generally run in the deploy step of your app or before running `keystone start`.
- `keystone start --with-migrations` - Runs the generated migrations then starts Keystone.
{% /if %}
## Prisma CLI

The primary reason you'll need to use the Prisma CLI in your Keystone project is to work with Prisma Migrate.

As you start working with more sophisticated migration scenarios, you'll probably also need to use the [`migrate resolve`](https://www.prisma.io/docs/reference/api-reference/command-reference/#migrate-resolve) and [`migrate status`](https://www.prisma.io/docs/reference/api-reference/command-reference/#migrate-status) commands.

While Keystone abstracts much of the Prisma workflow for you, we strongly recommend you familiarise yourself with the Prisma Migrate CLI commands when you are managing your application in production.


{% related-content %}
{% well
heading="Getting Started with create-keystone-app"
href="/docs/getting-started" %}
How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL Playground.
{% /well %}
{% well
heading="Command Line Guide"
href="/docs/guides/cli" %}
Learn how to use Keystone's command line interface (CLI) to develop, build, and deploy your Keystone projects.
{% /well %}
{% /related-content %}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { Context, TypeInfo } from '.keystone/types';

const db: KeystoneConfig<TypeInfo>['db'] = {
provider: 'sqlite',
// You should use migrations in production environments
useMigrations: false,
url: process.env.DATABASE_URL || 'file:./database.db',
async onConnect(context: Context) {
if (process.argv.includes('--seed-database')) {
Expand Down
2 changes: 0 additions & 2 deletions examples/e2e-boilerplate/keystone-server/keystone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { Context, TypeInfo } from '.keystone/types';

const db: KeystoneConfig<TypeInfo>['db'] = {
provider: 'sqlite',
// You should use migrations in production environments
useMigrations: false,
url: process.env.DATABASE_URL || 'file:./database.db',
async onConnect(context: Context) {
if (process.argv.includes('--seed-database')) {
Expand Down
2 changes: 0 additions & 2 deletions examples/feature-boilerplate/keystone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { Context, TypeInfo } from '.keystone/types';

const db: KeystoneConfig<TypeInfo>['db'] = {
provider: 'sqlite',
// You should use migrations in production environments
useMigrations: false,
url: process.env.DATABASE_URL || 'file:./database.db',
async onConnect(context: Context) {
if (process.argv.includes('--seed-database')) {
Expand Down
39 changes: 21 additions & 18 deletions packages/core/src/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,28 @@ export async function validateCommittedArtifacts(
return 'prisma';
}
})();
if (outOfDateSchemas) {
const message = {
both: 'Your Prisma and GraphQL schemas are not up to date',
graphql: 'Your GraphQL schema is not up to date',
prisma: 'Your Prisma schema is not up to date',
}[outOfDateSchemas];
console.log(message);
const term = {
both: 'Prisma and GraphQL schemas',
prisma: 'Prisma schema',
graphql: 'GraphQL schema',
}[outOfDateSchemas];
if (shouldPrompt && (await confirmPrompt(`Would you like to update your ${term}?`))) {
await writeCommittedArtifacts(artifacts, cwd);
} else {
console.log(`Please run keystone postinstall --fix to update your ${term}`);
throw new ExitError(1);
}
if (!outOfDateSchemas) return;

const message = {
both: 'Your Prisma and GraphQL schemas are not up to date',
graphql: 'Your GraphQL schema is not up to date',
prisma: 'Your Prisma schema is not up to date',
}[outOfDateSchemas];
console.log(message);

const which = {
both: 'Prisma and GraphQL schemas',
prisma: 'Prisma schema',
graphql: 'GraphQL schema',
}[outOfDateSchemas];

if (shouldPrompt && (await confirmPrompt(`Replace the ${which}?`))) {
await writeCommittedArtifacts(artifacts, cwd);
return;
}

console.log(`Use keystone dev to update the ${which}`);
throw new ExitError(1);
}

export async function writeCommittedArtifacts(artifacts: CommittedArtifacts, cwd: string) {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/lib/createSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export function createSystem(config: KeystoneConfig) {
});

return {
// TODO: remove, replace with server.onStart
async connect() {
await prismaClient.$connect();
await config.db.onConnect?.(context);
Expand Down
Loading