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

feat(gatsby): plugin option validation #27242

Merged
merged 17 commits into from
Oct 7, 2020
Merged

Conversation

mxstbr
Copy link
Contributor

@mxstbr mxstbr commented Oct 2, 2020

This implements plugin option validation if a plugin has a gatsbyNode.pluginOptionsSchema defined. (see #27166 for the RFC for the pluginOptionsSchema API)

I think we should disable this by default until we have documentation for it, added some more schemas to core plugins and (maybe) have tested it with a few alpha/beta testers! So, this PR adds a feature flag in the form of the GATSBY_EXPERIMENTAL_PLUGIN_OPTION_VALIDATION environment variable.

I added the Google Analytics option schema for testing. Here is an example of what a configuration error looks like in the terminal with these incorrect options:

{
  resolve: `gatsby-plugin-google-analytics`,
  options: {
    anonymize: `not a boolean`
  }
}

Screenshot 2020-10-05 at 11 48 27

[ch15946]

@gatsbot gatsbot bot added the status: triage needed Issue or pull request that need to be triaged and assigned to a reviewer label Oct 2, 2020
@LekoArts LekoArts removed the status: triage needed Issue or pull request that need to be triaged and assigned to a reviewer label Oct 5, 2020
@mxstbr mxstbr marked this pull request as ready for review October 5, 2020 12:53
@mxstbr mxstbr changed the title feat(gatsby): pluginOptionsSchema validation feat(gatsby): plugin option validation Oct 5, 2020
Copy link
Contributor

@laurieontech laurieontech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liking the structured errors!

Base automatically changed from gatsby-plugin-utils to master October 6, 2020 06:22
Copy link
Contributor

@ascorbic ascorbic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we able to add a definition for GatsbyNode["pluginOptionsSchema"] to gatsby/index.d.ts? I'm assuming we'll need to add our own type for Joi ones we extend it? Do you have any idea how that works in general?

@ascorbic
Copy link
Contributor

ascorbic commented Oct 6, 2020

Looking good!

@mxstbr mxstbr force-pushed the validation-plugin-options-schema branch from 47db081 to 3b96006 Compare October 6, 2020 11:42
Copy link
Contributor

@wardpeet wardpeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small nits and questions

Comment on lines 11 to 24
dotenv: {
args: [`name`],
validate(value, helpers, args): void {
if (!args.name) {
return helpers.error(
`any.dotenv requires the environment variable name`
)
}
return value
},
method(name): Schema {
return this.$_addRule({ name: `dotenv`, args: { name } })
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have forgotten but I'm still not sure why we want this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This let's plugin authors mark that a value entered during (a potential) gatsby plugin add command should be stored in the .env file instead of being written to the gatsby-config.js directly. E.g.:

// gatsby-plugin-source-contentful/gatsby-node.js
export const pluginOptionsSchema = ({ Joi }) => Joi.object({
  accessToken: Joi.string().required().dotenv("CONTENTFUL_ACCESS_TOKEN")
})

Then, when we prompt the user to enter their access token we will 1) mask the input in the CLI and 2) write the value to the .env file and process.env.CONTENTFUL_ACCESS_TOKEN to the gatsby-config.js 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still something I'm not 100% convinced about. The feature sounds really cool, but I fear that env vars can be similar and bring conflicts.

Can we strip it out until we have the need for it/more discussions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this the main way we can ensure core -> cloud compatibility? @wardpeet can you explain more about what conflicts you anticipate?

Copy link
Contributor

@wardpeet wardpeet Oct 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might not 100% understand it so let's say that I have plugin A that has dotenv('HOST') and a plugin B dotenv('HOST') how would this play out? Also what if for some reason I rather have CONTENTFUL_DELIVERY_TOKEN instead of CONTENTFUL_ACCESS_TOKEN?

What do you mean with core <-> cloud compatibility?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this isn't for the user to understand, but rather the plugin author. We could solve the duplicate problem by concatenating the plugin name and the option name. So GATSBY_PLUGIN_CONTENTFUL_HOST.

The core <-> compatibility is the idea that you'll always be in a valid state and you'd be ready to set up with cloud since it leverages process.env to hook into CMS keys and the like.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why I want to hold off on adding this feature cause it needs more thinking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have disabled (i.e. commented out) this extension for now until we decide on a fixed API for it to unblock this PR 👍

@MichaelDeBoey
Copy link
Contributor

@mxstbr Will it also be possible to validate that we don't pass any options anymore?
For instance in a previous version of a plugin you could pass some options, but they have been removed in a new major version of the plugin and the plugin author wants to notify the user about that.

@mxstbr
Copy link
Contributor Author

mxstbr commented Oct 7, 2020

Will it also be possible to validate that we don't pass any options anymore?
For instance in a previous version of a plugin you could pass some options, but they have been removed in a new major version of the plugin and the plugin author wants to notify the user about that.

This'll happen automatically! When you publish a new version with a changed options schema the user will get an error after upgrading telling them that they are using options that don't exist 👍

@openscript
Copy link
Contributor

I like the idea! .. but it brought some troubles to me. I'm using gatsby-plugin-ts-config to write typed configuration files. Now I'm forced to define a pluginOptionsSchema property, when I configure my GatsbyNode.

The comment says Currently experimental and not enabled by default. so why is it not typed as optional?

pluginOptionsSchema?(args: PluginOptionsSchemaArgs): ObjectSchema

@mxstbr
Copy link
Contributor Author

mxstbr commented Oct 12, 2020

Great catch @openscript, it should definitely be optional! Would you mind opening a new PR with that change? 🙏

Comment on lines -1 to -7
exports.onPreInit = ({ reporter }, options) => {
if (!options.trackingId) {
reporter.warn(
`The Google Analytics plugin requires a tracking ID. Did you mean to add it?`
)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mxstbr Shouldn't we have kept onPreInit in case GATSBY_EXPERIMENTAL_PLUGIN_OPTION_VALIDATION wasn't true? 🤔

If people update gatsby-plugin-google-analytics but don't update gatsby, they won't get any warning anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, good catch! PR welcome 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On it boss! 😉

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you go: #27495 🙂

@kamranayub
Copy link
Contributor

Hey team, working on a Gatsby plugins course and I wanted to feature this plugin options schema support but it appears that it isn't working for a local plugin. 🤔

I still have to dig into this PR/the code and see if I can confirm that's the issue. If so I'll open a new ticket and try and contribute a fix since I'd love to showcase this (non-local plugins are introduced later in the course and the local plugin in my demo is a good use case for options schema).

@KyleAMathews
Copy link
Contributor

That'd be sweet!

@kamranayub
Copy link
Contributor

Yes, looks like it does fail with a small test case so I will open an issue.

image

it(`validates local plugin schemas`, async () => {
      await loadPlugins({
        plugins: [
          {
            resolve: require.resolve('./__fixtures__/local-plugin'),
            options: {
              optionalString: 1234
            },
          },
        ],
      })

      expect(reporter.error as jest.Mock).toHaveBeenCalledTimes(1)
      expect(mockProcessExit).toHaveBeenCalledWith(1)
    })

@kamranayub
Copy link
Contributor

kamranayub commented Feb 26, 2021

For whoever would like to review, I have a proposed fix: #29787

pragmaticpat pushed a commit to pragmaticpat/gatsby that referenced this pull request Apr 28, 2022
* Make pluginOptionsSchema optional

@context: gatsbyjs#27242

* Exclude undefined pluginOptionsSchema

* Exclude undefined pluginOptionsSchema from plugin validation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants