Skip to content

Conversation

@ericlee878
Copy link
Contributor

@ericlee878 ericlee878 commented Nov 18, 2025

Resolves: https://github.com/orgs/shop/projects/208/views/34?pane=issue&itemId=139461468&issue=shop%7Cissues-api-foundations%7C1114 and https://github.com/orgs/shop/projects/208/views/34?pane=issue&itemId=139446074&issue=shop%7Cissues-api-foundations%7C1112

Why are these changes introduced?

Improves the validation and error handling for GraphQL operations in the bulk operations service.

Implementation Details

  • Enhances GraphQL document validation to ensure exactly one operation definition is present (error handling for cases that don't have exactly one operation)
  • Additional unit tests added that prove core automatically rejects malformed documents (we don't have to do this).
  • Created new validateGraphQLDocument() function that consolidates all GraphQL validation in one place:
    • Validates exactly one operation definition exists
    • Validates --variables flag is only used with mutations
    • Checks if the operation is a mutation (returns boolean that is used later). This replaces the previous isMutation() function.

Testing

Unit tests in execute-bulk-operation.test.ts

@ericlee878 ericlee878 changed the title add graphql operation validation Add GraphQL Operation Validation for Bulk Operations CLI Nov 18, 2025
Copy link
Contributor Author

ericlee878 commented Nov 18, 2025

@github-actions
Copy link
Contributor

We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run pnpm changeset add to track your changes and include them in the next release CHANGELOG.

Caution

DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 18, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
79.2% (-0.03% 🔻)
13652/17237
🟡 Branches
73.09% (-0.02% 🔻)
6651/9100
🟡 Functions
79.35% (-0.02% 🔻)
3520/4436
🟡 Lines
79.56% (-0.02% 🔻)
12894/16207
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / bulk-operation-run-mutation.ts
100% 100% 100% 100%
🟢
... / bulk-operation-run-query.ts
100% 100% 100% 100%
🟢
... / staged-uploads-create.ts
100% 100% 100% 100%
🟢
... / execute-bulk-operation.ts
96.15% 87.5% 100% 95.83%
🟢
... / run-mutation.ts
100% 100% 100% 100%
🟢
... / run-query.ts
100% 100% 100% 100%
🟡
... / stage-file.ts
74.29% 53.33% 85.71% 73.53%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / ConcurrentOutput.tsx
98.36% (-1.64% 🔻)
92% (-4% 🔻)
100%
98.33% (-1.67% 🔻)
🔴
... / ui.tsx
50.82% (-0.79% 🔻)
42.86% (-5.53% 🔻)
54.55% (+1.42% 🔼)
50% (-0.82% 🔻)
🟡
... / theme-environment.ts
69.57% (-1.86% 🔻)
50%
55.56% (-3.27% 🔻)
69.57% (-1.86% 🔻)

Test suite run success

3371 tests passing in 1380 suites.

Report generated by 🧪jest coverage report action from c316242

@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from bce09b0 to ff34685 Compare November 18, 2025 02:04
@ericlee878 ericlee878 force-pushed the 11-14-implement-erroring-for-query-with-variable branch from 742d51c to 1e7de33 Compare November 18, 2025 02:41
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from ff34685 to 71ee5db Compare November 18, 2025 02:41
@ericlee878 ericlee878 force-pushed the 11-14-implement-erroring-for-query-with-variable branch from 1e7de33 to 5b0a797 Compare November 18, 2025 22:14
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from 71ee5db to 0404698 Compare November 18, 2025 22:14
@ericlee878 ericlee878 force-pushed the 11-14-implement-erroring-for-query-with-variable branch from 5b0a797 to fc9f640 Compare November 18, 2025 22:17
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from 0404698 to 85156dc Compare November 18, 2025 22:17
@ericlee878 ericlee878 force-pushed the 11-14-implement-erroring-for-query-with-variable branch from fc9f640 to af1941b Compare November 18, 2025 22:27
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch 2 times, most recently from 290c967 to ac1fd53 Compare November 19, 2025 00:09
@ericlee878 ericlee878 force-pushed the 11-14-implement-erroring-for-query-with-variable branch from af1941b to 8582fa3 Compare November 19, 2025 21:19
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from ac1fd53 to 5c20695 Compare November 19, 2025 21:19
@ericlee878 ericlee878 force-pushed the 11-14-implement-erroring-for-query-with-variable branch from 8582fa3 to e9edae7 Compare November 19, 2025 21:23
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from 5c20695 to 3f00902 Compare November 19, 2025 21:23
@github-actions
Copy link
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/ui.d.ts
@@ -1,5 +1,4 @@
 import { FatalError as Fatal } from './error.js';
-import { TokenizedString } from './output.js';
 import { ConcurrentOutputProps } from '../../private/node/ui/components/ConcurrentOutput.js';
 import { handleCtrlC, render } from '../../private/node/ui.js';
 import { AlertOptions } from '../../private/node/ui/alert.js';
@@ -332,23 +331,21 @@ interface RenderTasksOptions {
  * Installing dependencies ...
  */
 export declare function renderTasks<TContext>(tasks: Task<TContext>[], { renderOptions, noProgressBar }?: RenderTasksOptions): Promise<TContext>;
-export interface RenderSingleTaskOptions<T> {
-    title: TokenizedString;
-    task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
-    renderOptions?: RenderOptions;
-}
 /**
- * Awaits a single task and displays a loading bar while it's in progress. The task's result is returned.
+ * Awaits a single promise and displays a loading bar while it's in progress. The promise's result is returned.
  * @param options - Configuration object
- * @param options.title - The initial title to display with the loading bar
- * @param options.task - The async task to execute. Receives an updateStatus callback to change the displayed title.
- * @param options.renderOptions - Optional render configuration
- * @returns The result of the task
+ * @param options.title - The title to display with the loading bar
+ * @param options.taskPromise - The promise to track
+ * @param renderOptions - Optional render configuration
+ * @returns The result of the promise
  * @example
  * ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  * Loading app ...
  */
-export declare function renderSingleTask<T>({ title, task, renderOptions }: RenderSingleTaskOptions<T>): Promise<T>;
+export declare function renderSingleTask<T>({ title, taskPromise }: {
+    title: string;
+    taskPromise: Promise<T> | (() => Promise<T>);
+}, { renderOptions }?: RenderTasksOptions): Promise<T>;
 export interface RenderTextPromptOptions extends Omit<TextPromptProps, 'onSubmit'> {
     renderOptions?: RenderOptions;
 }
packages/cli-kit/dist/private/node/ui/components/SingleTask.d.ts
@@ -1,9 +1,8 @@
-import { TokenizedString } from '../../../../public/node/output.js';
-interface SingleTaskProps<T> {
-    title: TokenizedString;
-    task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
-    onComplete?: (result: T) => void;
+import React from 'react';
+interface SingleTaskProps {
+    title: string;
+    taskPromise: Promise<unknown>;
     noColor?: boolean;
 }
-declare const SingleTask: <T>({ task, title, onComplete, noColor }: SingleTaskProps<T>) => JSX.Element | null;
+declare const SingleTask: ({ taskPromise, title, noColor }: React.PropsWithChildren<SingleTaskProps>) => JSX.Element | null;
 export { SingleTask };
\ No newline at end of file

}

function isMutation(graphqlOperation: string): boolean {
function validateGraphQLDocument(graphqlOperation: string, variables?: string[]): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

I find it weird that validateGraphQLDocument returns a boolean that doesn't represent if the graphql is valid or not, but if its a mutation. Someone reading just the signature of this function wouldn't understand that.

I see two options here:

  • Split in two: validateGraphQLDocument that returns nothing, just throws if invalid, and isMutation returns a boolean. Is ok to parse the document twice, is not a heavy operation afaik.
  • Type the return of validateGraphQLDocument to be something like:
type ValidationResult =
  | {
      result: 'ok'
      type: 'mutation' | 'query'
    }
  | {
      result: 'error'
      message: TokenItem | OutputMessage
    }

I'm ok with both, I think the first option would be cleaner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Refactored to the first option!

@graphite-app graphite-app bot changed the base branch from 11-14-implement-erroring-for-query-with-variable to graphite-base/6632 November 20, 2025 17:50
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from 3f00902 to 24f0ce6 Compare November 20, 2025 17:57
@ericlee878 ericlee878 changed the base branch from graphite-base/6632 to 11-14-implement-erroring-for-query-with-variable November 20, 2025 17:57
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from 24f0ce6 to c6e18b0 Compare November 20, 2025 18:00
Base automatically changed from 11-14-implement-erroring-for-query-with-variable to main November 20, 2025 18:26
@ericlee878 ericlee878 force-pushed the 11-17-malformed-graphql-operation-validation branch from c6e18b0 to c316242 Compare November 20, 2025 19:46
@ericlee878 ericlee878 added this pull request to the merge queue Nov 24, 2025
Merged via the queue into main with commit 61c28fd Nov 24, 2025
25 checks passed
@ericlee878 ericlee878 deleted the 11-17-malformed-graphql-operation-validation branch November 24, 2025 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants