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

Add support for a config file to the generate-persisted-query-manifest CLI #295

Merged
merged 12 commits into from
Jun 2, 2023

Conversation

jerelmiller
Copy link
Member

@jerelmiller jerelmiller commented Jun 2, 2023

The CLI can now take a config file that will be used for the operation extraction. The CLI uses cosmiconfig and will, by default, search for a config file in these locations:

  • .persisted-query-manifest.config.json
  • persisted-query-manifest.config.json
  • .persisted-query-manifest.config.yml
  • persisted-query-manifest.config.yml
  • .persisted-query-manifest.config.yaml
  • persisted-query-manifest.config.yaml
  • .persisted-query-manifest.config.js
  • persisted-query-manifest.config.js
  • .persisted-query-manifest.config.ts
  • persisted-query-manifest.config.ts
  • .persisted-query-manifest.config.cjs
  • persisted-query-manifest.config.cjs
  • A persisted-query-manifest key in package.json

You can also provide the location of the config file with the --config option to the CLI:

npx generate-persisted-query-manifest --config path/to/persisted-query-manifest.config.ts

The config file can be configured with the following options:

  • documents (string | string[]) - The glob patterns where the CLI tool should search for GraphQL operations.
    • Defaults to src/**/*.{graphql,js,jsx,ts,tsx}.
  • documentIgnorePatterns (string | string[]) - Glob patterns where the tool should exclude searching for GraphQL operations.
    • Defaults to ["**/*.d.ts", "**/*.spec.{js,jsx,ts,tsx}", "**/*.story.{js,jsx,ts,tsx}", "**/*.test.{js,jsx,ts,tsx}"]
  • output (string) - Path where the manifest should be written.
    • Defaults to persisted-query-manifest.json

When the config file is a TypeScript file, you can import the PersistedQueryManifestConfig type to get autocompletion and type checking on the config object.

// persisted-query-manifest.config.ts
import { PersistedQueryManifestConfig } from '@apollo/generate-persisted-query-manifest';

const config: PersistedQueryManifestConfig = {
  documents: 'path/to/documents/**/*.{ts,tsx}'
};

export default config;

@changeset-bot
Copy link

changeset-bot bot commented Jun 2, 2023

🦋 Changeset detected

Latest commit: 1e8a07d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@apollo/generate-persisted-query-manifest Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@jerelmiller jerelmiller requested a review from glasser June 2, 2023 17:28
@codesandbox-ci
Copy link

codesandbox-ci bot commented Jun 2, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.


globInclude?: string[];
globExclude?: string[];
export interface PersistedQueryManifestConfig {
Copy link
Member Author

Choose a reason for hiding this comment

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

I tweaked the names of these options. Let me know if you like these or prefer something different.

Copy link
Member

@glasser glasser left a comment

Choose a reason for hiding this comment

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

(heading out for a bit, feel free to make progress/merge/etc)

files.add(f);
}
],
output: "persisted-query-manifest.json",
Copy link
Member

Choose a reason for hiding this comment

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

I would lean towards stdout as the default (I'm not sure there are great defaults, most likely people want things under src, and it's a lot easier for folks to just change stdout to a file without even using a config file than to figure out what the program's shorthand for writing to stdout is?)

Copy link
Member Author

Choose a reason for hiding this comment

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

The reason I went this way is because our initial list of instructions included this command:

rover pq publish <GRAPH_REF> --manifest ./operations/pqs/pqm.json

This assumes a written file to read from. I'm fine changing it to stdout as the default if the plan is to document this command using stdout by default.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to merge as-is for now and we can revisit this topic 🙂

Copy link
Member

Choose a reason for hiding this comment

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

I still feel like printing to stdout is a better default.

If I have a CLI program that prints to stdout, I 100% of the time immediately know that if I'd rather it go to a file I can just use >.
If I have a CLI program that prints to a file, I have to figure out which convention it uses for stdout (-? STDOUT? something special?) in order to change it.

Plus it'll help remind us to take care to print any errors to stderr :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I respectfully disagree and I came to this decision for a couple reasons.

  1. Our work-in-progress documentation discusses in detail creating persisted query manifest files, which also shows examples of the rover command that uses a file to generate that list in GraphOS. I felt there would be a huge disconnect if we defaulted to stdout when our documentation encourages files.
  2. Files are trackable in git, and I expect many teams will want to see diffs in code reviews to understand what changes are made to query bodies. Writing to stdout is much more invisible and hard to understand what might be changing.

That being said, I see no reason why we couldn't add a CLI option that allows you to print the result to stdout/stderr in case people like that workflow better. I just wouldn't make this the default behavior.

Thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

Happy to agree to disagree (and leave it your way) here. But it does seem like something that would be helpful to be able to override on a per-execution basis rather than just in the config file, and with stdout as an easily achievable goal (which is I think what you're saying here).

(For example, if you have some sort of super custom transform that requires you to post-process the manifest file every time, it does seem like writing to stdout and using a pipe would be attractive.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh yes, sorry I should have mentioned that when I said "CLI option", I meant you'd do something like:

npx generate-persisted-query-manifest --stdout

(option name TBD)

This would override the output in your config file. I don't see this being an option you change in the config file itself.

Do you have recommendations on the option name? Not sure if there is a common convention in commands for this kind of thing or not.

packages/generate-persisted-query-manifest/src/index.ts Outdated Show resolved Hide resolved
const { Command } = require("commander");
const { cosmiconfig } = require("cosmiconfig");
const { generatePersistedQueryManifest, defaults } = require("./dist/index.js");
const { TypeScriptLoader } = require("cosmiconfig-typescript-loader");
Copy link
Member

Choose a reason for hiding this comment

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

I can't say I get the point of letting you load TS files if there's no obvious way to teach the TS file what the type it's supposed to return is? Or are you able to import PersistedQueryManifestConfig within the file?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep! You're able to import the type in the config file, which gives you autocompletion and inline docs for each option.

It looks like this (also in the PR description):

// persisted-query-manifest.config.ts
import { PersistedQueryManifestConfig } from '@apollo/generate-persisted-query-manifest';

const config: PersistedQueryManifestConfig = {
  documents: 'path/to/documents/**/*.{ts,tsx}'
};

export default config;

@jerelmiller jerelmiller merged commit c41dd06 into glasser/persisted-query-lists Jun 2, 2023
@jerelmiller jerelmiller deleted the jerel/config-file branch June 2, 2023 19:20
@jerelmiller jerelmiller changed the title Add support for a config file to the generate-persisted-query-manifeest CLI Add support for a config file to the generate-persisted-query-manifest CLI Jun 2, 2023
@github-actions github-actions bot mentioned this pull request Jun 2, 2023
const supportedExtensions = ["json", "yml", "yaml", "js", "ts", "cjs"];

const searchPlaces = supportedExtensions.flatMap((extension) => [
`.${moduleName}.config.${extension}`,
Copy link
Member

Choose a reason for hiding this comment

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

I'm not really sure that having the dot-prefix and the not-dot-prefix versions are both that valuable. It's twice as much to document and twice as many places to look for a thing? I thought this was just us using cosmiconfig defaults but if we're defining our own conventions then maybe we should just make a choice, especially since you can just pass -c if you want something different than our choice.

Copy link
Member Author

Choose a reason for hiding this comment

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

Prefixing with the dot would make it a hidden file and some may prefer that. I don't think its a bad thing to support both, especially because cosmiconfig does this out of the box. I'm sure we could find a way to make documentation succinct. I'm just not driven by "too much to document" as being the reason to limit the options here.

The reason I have searchPlaces to begin with and I don't just use cosmiconfig('persisted-query-manifest') is because the manifest file is written to persisted-query-manifest.json, which is included in list of files that cosmiconfig will look by default. To differentiate, I figured I'd enforce .config in the filename.

Copy link
Member

Choose a reason for hiding this comment

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

OK with an agree to disagree here too. I do think that letting people specify their own config filename means we can have a more opinionated default, but if your opinion is to have a vaguer opinion then I guess it's opinionated to be less opinionated :)

Copy link
Member Author

Choose a reason for hiding this comment

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

we can have a more opinionated default

I'm not necessarily against this. In fact, I'd say the search places I have here now are actually a bit more opinionated than the cosmiconfig defaults (I enforce .config.<ext>. cosmiconfig will search for rc files as well, etc).

In fact I could probably simplify how we look for this by saying:

Create a config file named persisted-query-manifest.config.<extension> where <extension> is one of json, yml, yaml, js, ts, or cjs. You may also prefix the file with a dot (.) if you prefer hidden files.

What would you like to see as a more opinionated default?

Copy link
Member

Choose a reason for hiding this comment

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

I do think that's a better way to document it than a long list. I guess my opinion would be to drop the final sentence and people who want hidden files are welcome to pass --config. But it's bikeshed-painting at this point.

Copy link
Member Author

Choose a reason for hiding this comment

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

True, but the reason I left it is because client teams are typically used to config files that support . in the name (jest, prettier, eslint, etc).

Agreed though, just bikeshedding at this point 😆

/**
* Paths to your GraphQL documents: queries, mutations, subscriptions, and fragments.
*/
documents?: string | string[];
Copy link
Member

Choose a reason for hiding this comment

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

A bit surprising that this doesn't have "patterns" in its name when the others do.

Copy link
Member Author

Choose a reason for hiding this comment

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

GraphQL Codegen, one of the most popular tools of its kind, uses documents for this exact thing. While its not necessarily a community convention, I figured using a name that another popular tool uses would make this feel a bit more familiar.

Copy link
Member

Choose a reason for hiding this comment

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

Should we just endeavor to be fully codegen-compatible (since many folks might use both tools) and let you specify your ignores here too with ! like codegen does? Looks like they use globby under the hood. (Or maybe we just should use @graphql-tools/code-file-loader which is one layer of wrapping up from the graphql-tag-pluck package we're using now?)

Copy link
Member Author

Choose a reason for hiding this comment

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

I considered that as well and would be happy to reduce the number of options here if we like this better. I opted to maintain them separate, but only because you had created them separate initially 😆.

Copy link
Member

Choose a reason for hiding this comment

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

I guess my main reaction was that it's weird to have "patterns" in one name and not the other; a nice way to resolve that is just "do the same exact thing as graphql-code-generator", and it looks like that might be relatively straightforward by switching to globby.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep for sure. Naming is hard and I couldn't think of anything better since documentsIgnore sounded weird and was on the fence of whether ignoredDocuments would make sense to people.

I'm all for simplifying to match graphql code generator 100% though so I'll make this change.

globExclude?: string[];
export interface PersistedQueryManifestConfig {
/**
* Paths to your GraphQL documents: queries, mutations, subscriptions, and fragments.
Copy link
Member

Choose a reason for hiding this comment

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

Would be helpful to define how the patterns work (even just by referring to "it's anything processed by the glob npm package")

Copy link
Member Author

Choose a reason for hiding this comment

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

For sure! I can provide an update here.

files.add(f);
}
],
output: "persisted-query-manifest.json",
Copy link
Member

Choose a reason for hiding this comment

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

I still feel like printing to stdout is a better default.

If I have a CLI program that prints to stdout, I 100% of the time immediately know that if I'd rather it go to a file I can just use >.
If I have a CLI program that prints to a file, I have to figure out which convention it uses for stdout (-? STDOUT? something special?) in order to change it.

Plus it'll help remind us to take care to print any errors to stderr :)

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.

2 participants