Skip to content

Conversation

@jordanverasamy
Copy link
Contributor

@jordanverasamy jordanverasamy commented Dec 2, 2025

WHY are these changes introduced?

https://github.com/shop/issues-api-foundations/issues/1095

We want to make sure it's clear to users when things are still running in the background.

WHAT is this pull request doing?

Let's helpfully print a nice message telling users when they can use the bulk status command, even if they CTRL+C out of an operation midway!

We did this by:

  • implementing a new optional onAbort callback to renderSingleTask, which you can use to configure custom behaviour when the user quits mid-way through a single task
  • teaching executeBulkOperation and watchBulkOperation to use that new onAbort callback to display a nice message when the user quits while watching a bulk operation

How to test your changes?

Without --watch, you get a nice help message:

image

With --watch, if you abort using CTRL+C before it's done, you get a nice help message:

CTRL+C-info-banner.mov

With --watch, without aborting, same behaviour as before this PR:

image

Copy link
Contributor Author

jordanverasamy commented Dec 2, 2025

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

@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch from c9dcbd0 to 282d7ce Compare December 3, 2025 17:34
@jordanverasamy jordanverasamy changed the title WIP -- Claude first draft WIP -- Claude attempts CTRL+C handling Dec 3, 2025
@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch 10 times, most recently from ab6f464 to 2db0cfe Compare December 4, 2025 00:54
@github-actions
Copy link
Contributor

github-actions bot commented Dec 4, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
79.16% (-0.06% 🔻)
13852/17498
🟡 Branches
73.13% (+0.02% 🔼)
6762/9247
🟡 Functions
79.33% (-0.04% 🔻)
3554/4480
🟡 Lines
79.53% (-0.05% 🔻)
13088/16457
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%
🟢
... / list-bulk-operations.ts
100% 100% 100% 100%
🟢
... / staged-uploads-create.ts
100% 100% 100% 100%
🔴
... / execute.ts
0% 0% 0% 0%
🔴
... / status.ts
0% 0% 0% 0%
🔴
... / pull.ts
0% 100% 0% 0%
🔴
... / pull.ts
0% 0% 0% 0%
🟢
... / bulk-operation-status.ts
96% 90.63% 100% 100%
🟢
... / download-bulk-operation-results.ts
100% 100% 100% 100%
🟢
... / execute-bulk-operation.ts
91.94% 84.21% 100% 93.22%
🟢
... / 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
🟢
... / 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% 🔻)
🟢
... / SingleTask.tsx
84.21% (-15.79% 🔻)
50% (-50% 🔻)
80% (-20% 🔻)
84.21% (-15.79% 🔻)
🔴
... / 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% 🔼)
🟢
... / init.ts
88% (-0.89% 🔻)
71.43% (+4.76% 🔼)
86.67% (+4.85% 🔼)
88% (-0.89% 🔻)
🟡
... / theme-polling.ts
67.12% (-0.93% 🔻)
68.75% 78.57%
66.67% (-0.98% 🔻)

Test suite run success

3451 tests passing in 1397 suites.

Report generated by 🧪jest coverage report action from df935ac

@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch 5 times, most recently from cfa7d4b to 88b4de5 Compare December 4, 2025 02:28
watch: true,
})

expect(watchBulkOperation).toHaveBeenCalledWith(mockAdminSession, createdBulkOperation.id)
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 don't think this assertion was providing actual value, since the thing we actually care about is that the success banner was rendered; I opted to just remove it instead of fixing the parameters on the assertion.)

watch: true,
})

expect(watchBulkOperation).toHaveBeenCalledWith(mockAdminSession, createdBulkOperation.id)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jordanverasamy jordanverasamy changed the title WIP -- Claude attempts CTRL+C handling Guide users to use bulk status when an operation is still running in the background Dec 4, 2025
@jordanverasamy jordanverasamy self-assigned this Dec 4, 2025
@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch from 88b4de5 to dd01d40 Compare December 4, 2025 02:40
)

if (abortController.signal.aborted) {
renderInfo({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made this an info banner per the brief, but I do think it looks a bit odd being all grey, maybe a success banner would more appropriately convey to the user "nothing went wrong, all is still good and running nicely". I'm not really sure. Let me know what you think is correct!

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree a success banner would be better. Actually, why not showing exactly the same message as when you run it without --watch?

╭─ success ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                                                                           │
│  Bulk operation started.                                                                                                                                  │
│                                                                                                                                                           │
│  Monitor its progress with:                                                                                                                               │
│  shopify app bulk status --id="gid://shopify/BulkOperation/5749231780082"                                                                                 │
│                                                                                                                                                           │
│    • ID: gid://shopify/BulkOperation/5749231780082                                                                                                        │
│    • Status: CREATED                                                                                                                                      │
│    • Created at: 2025-12-04T10:37:57Z                                                                                                                     │
│                                                                                                                                                           │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Copy link
Contributor Author

@jordanverasamy jordanverasamy Dec 4, 2025

Choose a reason for hiding this comment

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

Yeah, I considered this but decided it was a slightly different context so the most helpful possible messaging to the user is slightly different. I'll log this for Nick to think about though! TY!

Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is the Ctrl+C banner, I think info is correct, since it’s just informing you that the query is still running.

handleCtrlC(input, key)
}
},
{isActive: Boolean(isRawModeSupported)},
Copy link
Contributor Author

@jordanverasamy jordanverasamy Dec 4, 2025

Choose a reason for hiding this comment

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

This part is basically saying: only activate this behaviour if we're in an interactive terminal.

If STDIN isn't a TTY, for example if input is being piped, we're running in CI, or it's otherwise non-interactive, then isRawModeSupported will be false and the useInput hook will helpfully not do anything.

@jordanverasamy jordanverasamy marked this pull request as ready for review December 4, 2025 02:47
@jordanverasamy jordanverasamy requested a review from a team as a code owner December 4, 2025 02:47
@github-actions
Copy link
Contributor

github-actions bot commented Dec 4, 2025

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 changed the base branch from main to graphite-base/6678 December 4, 2025 03:38
@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch from dd01d40 to 0d6aee9 Compare December 4, 2025 03:38
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6678 to 12-02-move_command_from_shopify_app_execute_to_shopify_app_bulk_execute_ December 4, 2025 03:38
@jordanverasamy jordanverasamy changed the base branch from 12-02-move_command_from_shopify_app_execute_to_shopify_app_bulk_execute_ to graphite-base/6678 December 4, 2025 03:39
@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch from 0d6aee9 to 0a8232e Compare December 4, 2025 03:39
@jordanverasamy jordanverasamy changed the base branch from graphite-base/6678 to main December 4, 2025 03:39
@gonzaloriestra
Copy link
Contributor

/snapit

@github-actions
Copy link
Contributor

github-actions bot commented Dec 4, 2025

🫰✨ 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/cli@0.0.0-snapshot-20251204100354

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.

Nice improvement! Works great, just some suggestions and this small issue:

When you abort, it seems that it waits for the current polling sleep (up to 5 seconds) before actually finishing the command:

abort.mp4

Also, maybe you are already aware, but it's showing a duplicated ellipsis in the Starting task:

Image

Comment on lines 167 to 168
const command = outputToken.cyan(`shopify app bulk status --id="${operationId}"`)
return outputContent`Monitor its progress with:\n${command}`.value
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of manually choosing a different color, there's a standard way to print commands, see this example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wow, that's so nice, didn't know that! Adjusted, TY :)

)

if (abortController.signal.aborted) {
renderInfo({
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree a success banner would be better. Actually, why not showing exactly the same message as when you run it without --watch?

╭─ success ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                                                                           │
│  Bulk operation started.                                                                                                                                  │
│                                                                                                                                                           │
│  Monitor its progress with:                                                                                                                               │
│  shopify app bulk status --id="gid://shopify/BulkOperation/5749231780082"                                                                                 │
│                                                                                                                                                           │
│    • ID: gid://shopify/BulkOperation/5749231780082                                                                                                        │
│    • Status: CREATED                                                                                                                                      │
│    • Created at: 2025-12-04T10:37:57Z                                                                                                                     │
│                                                                                                                                                           │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

@jordanverasamy
Copy link
Contributor Author

When you abort, it seems that it waits for the current polling sleep (up to 5 seconds) before actually finishing the command:

That's very interesting, it shouldn't... I specifically used Promise.race to make sure we can get interrupted mid-sleep. I confirmed that I'm able to responsively and quickly exit mid-sleep on my machine. Wonder what's causing a difference between our environments 🤔

Also, maybe you are already aware, but it's showing a duplicated ellipsis in the Starting task:

Yeah, that extra ellipsis will get cleaned up, you pointed it out before so we've got it tracked by https://github.com/shop/issues-api-foundations/issues/1149. Thanks!!

@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch from 0a8232e to 143c488 Compare December 4, 2025 18:54
@jordanverasamy jordanverasamy force-pushed the jtv/ctrl-c-shows-how-to-resume branch from 143c488 to df935ac Compare December 4, 2025 19:01
@github-actions
Copy link
Contributor

github-actions bot commented Dec 4, 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/ui.d.ts
@@ -335,6 +335,7 @@ export declare function renderTasks<TContext>(tasks: Task<TContext>[], { renderO
 export interface RenderSingleTaskOptions<T> {
     title: TokenizedString;
     task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
+    onAbort?: () => void;
     renderOptions?: RenderOptions;
 }
 /**
@@ -348,7 +349,7 @@ export interface RenderSingleTaskOptions<T> {
  * ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  * Loading app ...
  */
-export declare function renderSingleTask<T>({ title, task, renderOptions }: RenderSingleTaskOptions<T>): Promise<T>;
+export declare function renderSingleTask<T>({ title, task, onAbort, renderOptions, }: RenderSingleTaskOptions<T>): Promise<T>;
 export interface RenderTextPromptOptions extends Omit<TextPromptProps, 'onSubmit'> {
     renderOptions?: RenderOptions;
 }
packages/cli-kit/dist/private/node/ui/components/SingleTask.d.ts
@@ -3,7 +3,8 @@ interface SingleTaskProps<T> {
     title: TokenizedString;
     task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
     onComplete?: (result: T) => void;
+    onAbort?: () => void;
     noColor?: boolean;
 }
-declare const SingleTask: <T>({ task, title, onComplete, noColor }: SingleTaskProps<T>) => JSX.Element | null;
+declare const SingleTask: <T>({ task, title, onComplete, onAbort, noColor }: SingleTaskProps<T>) => JSX.Element | null;
 export { SingleTask };
\ No newline at end of file

@jordanverasamy jordanverasamy added this pull request to the merge queue Dec 4, 2025
Merged via the queue into main with commit 850191c Dec 4, 2025
25 checks passed
@jordanverasamy jordanverasamy deleted the jtv/ctrl-c-shows-how-to-resume branch December 4, 2025 19:17
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