Skip to content

Conversation

@ericlee878
Copy link
Contributor

@ericlee878 ericlee878 commented Nov 24, 2025

Resolves: https://github.com/orgs/shop/projects/208/views/34?pane=issue&itemId=139444955&issue=shop%7Cissues-api-foundations%7C1111

Inspired by: https://app.graphite.com/github/pr/Shopify/cli/6588/Initial-Setup-Bulk-Operations-Infrastructure-for-Shopify-CLI#comment-PRRC_kwDOHibhHs6WnBvj

Summary

This PR enables users to pipe GraphQL queries into shopify app execute via stdin, improving the developer experience for bulk operations.

Why This Change Matters

Before: Users had to pass queries inline via --query, which is cumbersome for complex multi-line GraphQL:

shopify app execute --query 'query { products(first: 100) { edges { node { id title variants(first: 10) { edges { node { id price } } } } } } }'

After: Users can pipe from files or other commands:

cat my-query.graphql | shopify app execute

This aligns with Unix conventions and how developers already work with GraphQL tooling.

Design Decisions

  1. Stdin utilities in cli-kit/system.ts
    • Placing isStdinPiped() and readStdin() in system.ts alongside other process utilities makes them discoverable and reusable for future commands.
  2. Early return when TTY
    • readStdin() returns undefined immediately when stdin is interactive. This prevents the command from hanging waiting for user input — a common pitfall in CLI tools.

Thoughts for Future

  • Consider adding to command help text — The flag description mentions stdin, but --help output could include an example.

@ericlee878 ericlee878 marked this pull request as ready for review November 25, 2025 00:03
@ericlee878 ericlee878 requested a review from a team as a code owner November 25, 2025 00:03
@github-actions
Copy link
Contributor

github-actions bot commented Nov 25, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
79.22% (-0.01% 🔻)
13791/17408
🟡 Branches
73.13% (+0.03% 🔼)
6732/9205
🟡 Functions
79.32% (-0.05% 🔻)
3541/4464
🟡 Lines
79.59% (+0.01% 🔼)
13032/16373
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / admin-as-app.ts
100% 100% 100% 100%
🟢
... / bulk-operation-run-mutation.ts
100% 100% 100% 100%
🟢
... / bulk-operation-run-query.ts
100% 100% 100% 100%
🟢
... / get-bulk-operation-by-id.ts
100% 100% 100% 100%
🟢
... / staged-uploads-create.ts
100% 100% 100% 100%
🔴
... / status.ts
0% 100% 0% 0%
🟢
... / bulk-operation-status.ts
96% 85.71% 100% 100%
🟢
... / download-bulk-operation-results.ts
100% 100% 100% 100%
🟢
... / execute-bulk-operation.ts
90.91% 80.56% 100% 92.31%
🟢
... / format-bulk-operation-status.ts
100% 100% 100% 100%
🟢
... / run-mutation.ts
100% 100% 100% 100%
🟢
... / run-query.ts
100% 100% 100% 100%
🟡
... / stage-file.ts
72.73% 62.5% 83.33% 71.88%
🟢
... / watch-bulk-operation.ts
100% 100% 100% 100%
🔴
... / promiseWithResolvers.ts
33.33% 50% 50% 33.33%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🔴
... / execute.ts
0%
0% (-100% 🔻)
0% 0%
🟢
... / extension-instance.ts
84.8% (+0.23% 🔼)
77.6% (-0.91% 🔻)
92.06% (+0.13% 🔼)
85.11% (+0.24% 🔼)
🟡
... / specification.ts
69.09%
75.61% (+2.44% 🔼)
76.47% (-1.31% 🔻)
68.75%
🟢
... / ui_extension.ts
85.38% (-9.44% 🔻)
72.34% (-8.91% 🔻)
84% (-16% 🔻)
88% (-8.46% 🔻)
🟢
... / developer-platform-client.ts
84.62% (-1.5% 🔻)
73.68% (+3.1% 🔼)
81.82% (+1.82% 🔼)
90.63% (-2.71% 🔻)
🟢
... / api.ts
87.07% (-0.43% 🔻)
76.71% (-0.1% 🔻)
100%
86.49% (-0.43% 🔻)
🔴
... / ui.tsx
50.82% (-0.79% 🔻)
42.86% (-5.53% 🔻)
54.55% (+1.42% 🔼)
50% (-0.82% 🔻)
🟢
... / console.ts
81.82% (+15.15% 🔼)
75% (-25% 🔻)
100% (+33.33% 🔼)
81.82% (+15.15% 🔼)
🔴
... / dev.ts
14.29% (+0.95% 🔼)
3.13% (+0.18% 🔼)
50% (-7.14% 🔻)
14.29% (+0.95% 🔼)
🟡
... / theme-polling.ts
67.12% (-0.93% 🔻)
68.75% 78.57%
66.67% (-0.98% 🔻)

Test suite run success

3434 tests passing in 1393 suites.

Report generated by 🧪jest coverage report action from b4e7710

@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.

@ericlee878 ericlee878 force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch 2 times, most recently from 87db939 to 0a2627f Compare November 25, 2025 00:11
@ericlee878 ericlee878 requested a review from a team as a code owner November 25, 2025 00:11
Comment on lines 210 to 220
export function isStdinPiped(): boolean {
return !process.stdin.isTTY
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that piped implies non TTY, but non TTY doesn't always mean piped 🤔
I might be wrong, but CI environments are non TTY by default and that doesn't mean you are receiving an input via stdin

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right! I changed it so that the function now checks what stdin actually is using fstatSync(0): isFIFO() for pipes, isFile() for file redirects.

@ericlee878 ericlee878 force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from 0a2627f to 48b819c Compare November 25, 2025 14:32
@ericlee878 ericlee878 force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from 48b819c to d6cdf64 Compare November 25, 2025 14:38
@ericlee878 ericlee878 force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from e9bb7f5 to a0b57c8 Compare November 25, 2025 14:49
@ericlee878 ericlee878 force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from d6cdf64 to 38bd5b0 Compare November 25, 2025 14:49
@graphite-app graphite-app bot changed the base branch from 11-19-implement-ensureAuthenticatedAdminAsApp to graphite-base/6663 November 26, 2025 19:37
@jordanverasamy jordanverasamy force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from 38bd5b0 to e6c20a9 Compare November 27, 2025 03:45
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6663 to 11-19-implement-ensureAuthenticatedAdminAsApp November 27, 2025 03:45
@jordanverasamy jordanverasamy force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from 386074f to 479bccb Compare November 27, 2025 03:51
@jordanverasamy jordanverasamy force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from e6c20a9 to bf064cc Compare November 27, 2025 03:51
@jordanverasamy jordanverasamy changed the base branch from 11-19-implement-ensureAuthenticatedAdminAsApp to graphite-base/6663 November 27, 2025 16:30
@jordanverasamy jordanverasamy force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from bf064cc to 6d3b3fc Compare November 27, 2025 17:22
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6663 to 11-19-implement-ensureAuthenticatedAdminAsApp November 27, 2025 17:22
Base automatically changed from 11-19-implement-ensureAuthenticatedAdminAsApp to main November 27, 2025 17:42
return query
}

const stdinContent = await readStdin()
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this is the right layer to read from STDIN? Perhaps the command layer e.g. execute​ where input flags etc. are being parsed would be the right moment to check whether we've been given an input text/file?

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 call. I refactored it this way and made the code way more organized. Thanks!

@ericlee878 ericlee878 force-pushed the 11-24-Stdin-for-query-input-BulkOps-CLI branch from 6d3b3fc to b4e7710 Compare December 1, 2025 21:59
@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

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/system.d.ts
@@ -62,4 +62,23 @@ export declare function isCI(): boolean;
  *
  * @returns True if the current environment is a WSL environment.
  */
-export declare function isWsl(): Promise<boolean>;
\ No newline at end of file
+export declare function isWsl(): Promise<boolean>;
+/**
+ * Check if stdin has piped data available.
+ * This distinguishes between actual piped input (e.g., )
+ * and non-TTY environments without input (e.g., CI).
+ *
+ * @returns True if stdin is receiving piped data or file redirect, false otherwise.
+ */
+export declare function isStdinPiped(): boolean;
+/**
+ * Reads all data from stdin and returns it as a string.
+ * This is useful for commands that accept input via piping.
+ *
+ * @example
+ * // Usage: echo "your query" | shopify app execute
+ * const query = await readStdin()
+ *
+ * @returns A promise that resolves with the stdin content, or undefined if stdin is a TTY.
+ */
+export declare function readStdin(): Promise<string | undefined>;
\ No newline at end of file

@ericlee878 ericlee878 requested a review from dmerand December 1, 2025 22:03
Copy link
Contributor

@dmerand dmerand left a comment

Choose a reason for hiding this comment

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

I didn't tophat, but code LGTM. Thanks for the changes!

@ericlee878 ericlee878 added this pull request to the merge queue Dec 1, 2025
Merged via the queue into main with commit fb2af80 Dec 1, 2025
25 checks passed
@ericlee878 ericlee878 deleted the 11-24-Stdin-for-query-input-BulkOps-CLI branch December 1, 2025 22:18
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.

3 participants