Skip to content

Conversation

@jordanverasamy
Copy link
Contributor

@jordanverasamy jordanverasamy commented Nov 11, 2025

Issue: https://github.com/shop/issues-api-foundations/issues/1093

WHY are these changes introduced?

We want users to be able to pass a --watch flag, so they can monitor the progress and completion of their bulk operations directly from the CLI.

WHAT is this pull request doing?

  • Adds a new GraphQL query GetBulkOperationById to fetch the status and details of a bulk operation
  • Adds a new function watchBulkOperation that polls a bulk operation and displays live progress updates, using the new renderSingleTask async functionality added by Refactor renderSingleTask to allow an async process to update current status #6631
  • Adds a --watch flag to the app execute command that controls whether to use watchBulkOperation

How to test your changes?

Bulk queries

Verify that when --watch is provided, we see live updates printed to the terminal, then eventually a final screen when it finishes:

pnpm shopify app execute --path=<YOUR_TEST_APP> --query="{ products { edges { node { id } } } }" --watch
export-with-watch.mov

Next, verify that when --watch is not provided, the execute command prints some info about the bulk operation and returns right away, just like before this PR:

pnpm shopify app execute --path=<YOUR_TEST_APP> --query="{ products { edges { node { id } } } }"
export-without-watch.mov

Then do the same tests for bulk mutations:

Bulk mutations

With --watch:

pnpm shopify app execute \
--path=<YOUR_TEST_APP> \
--query='mutation createProduct($productSet: ProductSetInput!) { productSet(synchronous: true, input: $productSet) { product { id } } }' \
--variables='{ "productSet": { "title": "Winter hat" } }' \
--variables='{ "productSet": { "title": "Winter coat" } }' \
--variables='{ "productSet": { "title": "Winter pants" } }' \
--watch
import-with-watch.mov

Without --watch:

pnpm shopify app execute \
--path=<YOUR_TEST_APP> \
--query='mutation createProduct($productSet: ProductSetInput!) { productSet(synchronous: true, input: $productSet) { product { id } } }' \
--variables='{ "productSet": { "title": "Winter hat" } }' \
--variables='{ "productSet": { "title": "Winter coat" } }' \
--variables='{ "productSet": { "title": "Winter pants" } }' \
import-without-watch.mov

Copy link
Contributor Author

jordanverasamy commented Nov 11, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@jordanverasamy jordanverasamy changed the title introduce --watch flag [Bulk Operations CLI] show live progress updates when --watch is provided Nov 11, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 11, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
79.28% (+0.05% 🔼)
13718/17303
🟡 Branches
73.2% (+0.09% 🔼)
6697/9149
🟡 Functions
79.41% (+0.04% 🔼)
3529/4444
🟡 Lines
79.64% (+0.06% 🔼)
12963/16276
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%
🟢
... / execute-bulk-operation.ts
97.92% 90.63% 100% 97.83%
🟢
... / 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%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟡
... / specification.ts
68.52% (-0.57% 🔻)
75.61% (+2.44% 🔼)
76.47% (-1.31% 🔻)
68.09% (-0.66% 🔻)
🟢
... / 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% 🔻)
🟢
... / 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% 🔻)
🟢
... / console.ts
81.82% (+15.15% 🔼)
75% (-25% 🔻)
100% (+33.33% 🔼)
81.82% (+15.15% 🔼)
🔴
... / dev.ts
12.77% (-0.57% 🔻)
2.78% (-0.16% 🔻)
57.14%
12.77% (-0.57% 🔻)
🟡
... / theme-environment.ts
69.57% (-1.86% 🔻)
50%
55.56% (-3.27% 🔻)
69.57% (-1.86% 🔻)

Test suite run success

3402 tests passing in 1384 suites.

Report generated by 🧪jest coverage report action from 4c19852

@jordanverasamy jordanverasamy marked this pull request as ready for review November 11, 2025 00:45
@jordanverasamy jordanverasamy requested a review from a team as a code owner November 11, 2025 00:45
@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.

@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from 3d9e66e to 5d6b5d5 Compare November 11, 2025 00:48
@jordanverasamy jordanverasamy requested a review from a team as a code owner November 11, 2025 00:48
@ericlee878 ericlee878 changed the base branch from 11-07-implement_simple_bulk_query to graphite-base/6595 November 11, 2025 00:49
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from 5d6b5d5 to 153d57c Compare November 11, 2025 01:06
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6595 to 11-07-implement_simple_bulk_query November 11, 2025 01:06
@jordanverasamy jordanverasamy self-assigned this Nov 11, 2025
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from 153d57c to c324f49 Compare November 11, 2025 01:14
@ericlee878 ericlee878 changed the base branch from 11-07-implement_simple_bulk_query to graphite-base/6595 November 11, 2025 01:20
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from 2e960b1 to 594e201 Compare November 13, 2025 18:18
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from 594e201 to 500737d Compare November 13, 2025 18:19
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6595 to 11-07-implement_simple_bulk_query November 13, 2025 18:19
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch 5 times, most recently from 68dff49 to c4027ba Compare November 13, 2025 23:04
@ericlee878 ericlee878 changed the base branch from 11-07-implement_simple_bulk_query to graphite-base/6595 November 14, 2025 00:26
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from c4027ba to db8e837 Compare November 14, 2025 00:35
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6595 to 11-07-implement_simple_bulk_query November 14, 2025 00:35
} else {
renderSuccess({headline, customSections})
}
break
Copy link
Contributor

Choose a reason for hiding this comment

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

[nit] Would it be better to use renderWarning here for other cases? Not too sure so would like to hear your opinion.

Like

Suggested change
break
break
case 'CANCELED':
case 'CANCELING':
case 'EXPIRED':
renderWarning({headline, customSections})
break

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I considered this, no strong feelings either way. Happy to change it for now if you like. Let's check in with @nickwesselman about this once he's back from Thanksgiving.

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, those states should be shown as errors because the query didn't finish successfully, so I think it's ok as it is.

Copy link
Contributor

ericlee878 commented Nov 22, 2025

Everything looks good to me! Great tophatting video btw 👍

@gonzaloriestra
Copy link
Contributor

/snapit

@github-actions
Copy link
Contributor

🫰✨ Thanks @gonzaloriestra! Your snapshot has been published to npm.

Test the snapshot by installing your package globally:

npm i -g --@shopify:registry=https://registry.npmjs.org @shopify/[email protected]

Caution

After installing, validate the version by running just shopify in your terminal.
If the versions don't match, you might have multiple global instances installed.
Use which shopify to find out which one you are running and uninstall it.

Copy link
Contributor

@gonzaloriestra gonzaloriestra left a comment

Choose a reason for hiding this comment

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

LGTM! Tested that it works as expected.

I left a bunch of suggestions, mostly about UX.

Comment on lines +70 to +78
const createdOperation = bulkOperationResponse?.bulkOperation
if (createdOperation) {
if (watch) {
const finishedOperation = await watchBulkOperation(adminSession, createdOperation.id)
renderBulkOperationResult(finishedOperation)
} else {
renderBulkOperationResult(createdOperation)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What about simplifying this way? Improving the error message with something more useful if possible.

Suggested change
const createdOperation = bulkOperationResponse?.bulkOperation
if (createdOperation) {
if (watch) {
const finishedOperation = await watchBulkOperation(adminSession, createdOperation.id)
renderBulkOperationResult(finishedOperation)
} else {
renderBulkOperationResult(createdOperation)
}
}
let operation = bulkOperationResponse?.bulkOperation
if (!operation) throw new AbortError('Something went wrong when creating the bulk operation')
if (watch) operation = await watchBulkOperation(adminSession, createdOperation.id)
renderBulkOperationResult(operation)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm. Fair suggestion, thanks for thinking it through!

I think I like the way it is currently more, even though it's more lines. The current structure has different names for the operation -- finishedOperation vs createdOperation -- which communicates explicitly the expected state of the operation in each case. That makes it easier to grok at a glance for me, but I dunno, maybe that's just a me thing?

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 think I'm opting to leave it as is for now, but if you feel strongly let me know and I'm happy to adjust in a follow-up :)

Copy link
Contributor

Choose a reason for hiding this comment

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

No problem, I don't have a strong opinion.

What I don't like about the current approach is that it does nothing when createdOperation is undefined. But maybe that's not possible...

} else {
renderSuccess({headline, customSections})
}
break
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, those states should be shown as errors because the query didn't finish successfully, so I think it's ok as it is.

@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from 0804636 to c8e62d6 Compare November 26, 2025 18:35
@jordanverasamy jordanverasamy force-pushed the jtv/watch-live-progress branch from c8e62d6 to 4c19852 Compare November 26, 2025 18:51
@jordanverasamy jordanverasamy added this pull request to the merge queue Nov 26, 2025
Merged via the queue into main with commit 9dd0147 Nov 26, 2025
25 checks passed
@jordanverasamy jordanverasamy deleted the jtv/watch-live-progress branch November 26, 2025 19:33
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.

4 participants