Skip to content

Add JSON progress and retry support to task runners - #8672

Merged
gonzaloriestra merged 1 commit into
mainfrom
gonzalo/json-render-tasks
Sep 29, 2026
Merged

gonzaloriestra merged 1 commit into
mainfrom
gonzalo/json-render-tasks

Conversation

@gonzaloriestra

@gonzaloriestra gonzaloriestra commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

Task lists need to run without terminal UI in JSON mode, and progress consumers need to see retries and final failures.

WHAT is this pull request doing?

Run renderTasks without Ink in JSON mode while preserving shared context, subtasks, retries, and skipped tasks. Both task runners emit retry and failure events, and renderSingleTask gains an optional retry count that defaults to zero.

Theme commands adopt this support higher in the stack.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • Added a minor changeset for the public cli-kit additions.

@github-actions github-actions Bot added the Area: @shopify/app @shopify/app package issues label Sep 25, 2026
@gonzaloriestra
gonzaloriestra added this pull request to stack #8673 September 25, 2026 12:29
@gonzaloriestra
gonzaloriestra marked this pull request as ready for review September 28, 2026 08:19
@gonzaloriestra
gonzaloriestra requested a review from a team as a code owner September 28, 2026 08:19
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-render-tasks branch from 4f39011 to 2a52c56 Compare September 28, 2026 08:20
@github-actions github-actions Bot added no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. and removed Area: @shopify/app @shopify/app package issues labels Sep 28, 2026
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-render-tasks branch from 2a52c56 to 1a9d580 Compare September 28, 2026 10:25

@fredericoo fredericoo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

one more thing: since this changes the behaviour of a public cli-kit API for every plugin (not just theme commands), could the changeset in #8682 get a line for @shopify/cli-kit along the lines of "renderTasks runs without Ink and emits JSON progress events in JSON mode"? Right now it only mentions theme commands, so plugin authors wouldn't know.

Comment thread packages/cli-kit/src/public/node/ui.tsx
Comment thread packages/cli-kit/src/private/node/ui/tasks.ts
Comment thread packages/cli-kit/src/public/node/ui.test.ts Outdated
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-render-tasks branch from 1a9d580 to 7db949b Compare September 29, 2026 10:28
@gonzaloriestra gonzaloriestra changed the title Add JSON progress support to renderTasks Add JSON progress and retry support to task runners Sep 29, 2026
@gonzaloriestra gonzaloriestra removed the no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. label Sep 29, 2026
@github-actions github-actions Bot added the Area: @shopify/cli @shopify/cli package issues label Sep 29, 2026
Comment thread packages/cli-kit/src/private/node/ui/tasks.ts Outdated
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-render-tasks branch from 7db949b to 2321422 Compare September 29, 2026 13:44
Comment thread packages/cli-kit/src/private/node/ui/components/Tasks.tsx Outdated

@isaacroldan isaacroldan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a minor comment about the onComplete

@gonzaloriestra
gonzaloriestra added this pull request to the merge queue Sep 29, 2026
@gonzaloriestra
gonzaloriestra removed this pull request from the merge queue due to a manual request Sep 29, 2026
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-render-tasks branch from 2321422 to 58d1f09 Compare September 29, 2026 14:18
@github-actions

Copy link
Copy Markdown
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

packages/cli-kit/dist/private/node/ui/tasks.d.ts
import { TokenizedString } from '../../../public/node/output.js';
export interface Task<TContext = unknown> {
    title: string | TokenizedString;
    task: (ctx: TContext, task: Task<TContext>) => Promise<void | Task<TContext>[]>;
    retry?: number;
    retryCount?: number;
    errors?: Error[];
    skip?: (ctx: TContext) => boolean;
}
export declare function runTasks<TContext>(tasks: Task<TContext>[], onTask?: (task: Task<TContext>) => void): Promise<TContext>;

Existing type declarations

packages/cli-kit/dist/public/common/command-events.d.ts
@@ -23,14 +23,14 @@ export declare const commandDiagnosticEventSchema: z.ZodObject<{
 export declare const commandProgressEventSchema: z.ZodObject<{
     type: z.ZodLiteral<"progress">;
     timestamp: z.ZodString;
-    status: z.ZodEnum<["started", "updated", "completed"]>;
+    status: z.ZodEnum<["started", "updated", "retrying", "completed", "failed"]>;
     operation: z.ZodString;
     message: z.ZodOptional<z.ZodString>;
     current: z.ZodOptional<z.ZodNumber>;
     total: z.ZodOptional<z.ZodNumber>;
 }, "strict", z.ZodTypeAny, {
     type: "progress";
-    status: "started" | "updated" | "completed";
+    status: "started" | "updated" | "retrying" | "completed" | "failed";
     timestamp: string;
     operation: string;
     message?: string | undefined;
@@ -38,7 +38,7 @@ export declare const commandProgressEventSchema: z.ZodObject<{
     total?: number | undefined;
 }, {
     type: "progress";
-    status: "started" | "updated" | "completed";
+    status: "started" | "updated" | "retrying" | "completed" | "failed";
     timestamp: string;
     operation: string;
     message?: string | undefined;
@@ -67,14 +67,14 @@ export declare const commandEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
 }>, z.ZodObject<{
     type: z.ZodLiteral<"progress">;
     timestamp: z.ZodString;
-    status: z.ZodEnum<["started", "updated", "completed"]>;
+    status: z.ZodEnum<["started", "updated", "retrying", "completed", "failed"]>;
     operation: z.ZodString;
     message: z.ZodOptional<z.ZodString>;
     current: z.ZodOptional<z.ZodNumber>;
     total: z.ZodOptional<z.ZodNumber>;
 }, "strict", z.ZodTypeAny, {
     type: "progress";
-    status: "started" | "updated" | "completed";
+    status: "started" | "updated" | "retrying" | "completed" | "failed";
     timestamp: string;
     operation: string;
     message?: string | undefined;
@@ -82,7 +82,7 @@ export declare const commandEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
     total?: number | undefined;
 }, {
     type: "progress";
-    status: "started" | "updated" | "completed";
+    status: "started" | "updated" | "retrying" | "completed" | "failed";
     timestamp: string;
     operation: string;
     message?: string | undefined;
packages/cli-kit/dist/public/node/command-events.d.ts
@@ -29,14 +29,14 @@ export declare const commandEventOutputSchema: import("./json-output-schema.js")
 }>, import("zod").ZodObject<{
     type: import("zod").ZodLiteral<"progress">;
     timestamp: import("zod").ZodString;
-    status: import("zod").ZodEnum<["started", "updated", "completed"]>;
+    status: import("zod").ZodEnum<["started", "updated", "retrying", "completed", "failed"]>;
     operation: import("zod").ZodString;
     message: import("zod").ZodOptional<import("zod").ZodString>;
     current: import("zod").ZodOptional<import("zod").ZodNumber>;
     total: import("zod").ZodOptional<import("zod").ZodNumber>;
 }, "strict", import("zod").ZodTypeAny, {
     type: "progress";
-    status: "started" | "updated" | "completed";
+    status: "started" | "updated" | "retrying" | "completed" | "failed";
     timestamp: string;
     operation: string;
     message?: string | undefined;
@@ -44,7 +44,7 @@ export declare const commandEventOutputSchema: import("./json-output-schema.js")
     total?: number | undefined;
 }, {
     type: "progress";
-    status: "started" | "updated" | "completed";
+    status: "started" | "updated" | "retrying" | "completed" | "failed";
     timestamp: string;
     operation: string;
     message?: string | undefined;
packages/cli-kit/dist/public/node/ui.d.ts
@@ -318,6 +318,8 @@ export declare function renderTasks<TContext>(tasks: Task<TContext>[], { renderO
 export interface RenderSingleTaskOptions<T> {
     title: TokenizedString;
     task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
+    /** The number of additional attempts after a failure. Defaults to zero. */
+    retry?: number;
     onAbort?: () => void;
     renderOptions?: RenderOptions;
 }
@@ -326,12 +328,13 @@ export interface RenderSingleTaskOptions<T> {
  * @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.retry - The number of additional attempts after a failure. Defaults to zero.
  * @param options.renderOptions - Optional render configuration
  * @returns The result of the task
  * @example
  * Loading app ...
  */
-export declare function renderSingleTask<T>({ title, task, onAbort, renderOptions, }: RenderSingleTaskOptions<T>): Promise<T>;
+export declare function renderSingleTask<T>({ title, task, retry, onAbort, renderOptions, }: RenderSingleTaskOptions<T>): Promise<T>;
 export interface RenderTextPromptOptions extends Omit<TextPromptProps, 'onSubmit'> {
     renderOptions?: RenderOptions;
 }
packages/cli-kit/dist/private/node/ui/hooks/use-async-and-unmount.d.ts
@@ -1,6 +1,6 @@
-interface Options {
-    onFulfilled?: () => unknown;
+interface Options<T> {
+    onFulfilled?: (result: T) => unknown;
     onRejected?: (error: Error) => void;
 }
-export default function useAsyncAndUnmount(asyncFunction: () => Promise<unknown>, { onFulfilled, onRejected }?: Options): void;
+export default function useAsyncAndUnmount<T>(asyncFunction: () => Promise<T>, { onFulfilled, onRejected }?: Options<T>): void;
 export {};
\ No newline at end of file
packages/cli-kit/dist/private/node/ui/components/Tasks.d.ts
@@ -1,14 +1,7 @@
 import { AbortSignal } from '../../../../public/node/abort.js';
-import { TokenizedString } from '../../../../public/node/output.js';
+import { Task } from '../tasks.js';
 import React from 'react';
-export interface Task<TContext = unknown> {
-    title: string | TokenizedString;
-    task: (ctx: TContext, task: Task<TContext>) => Promise<void | Task<TContext>[]>;
-    retry?: number;
-    retryCount?: number;
-    errors?: Error[];
-    skip?: (ctx: TContext) => boolean;
-}
+export type { Task } from '../tasks.js';
 interface TasksProps<TContext> {
     tasks: Task<TContext>[];
     silent?: boolean;

@gonzaloriestra
gonzaloriestra added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit cafb9e6 Sep 29, 2026
30 checks passed
@gonzaloriestra
gonzaloriestra deleted the gonzalo/json-render-tasks branch September 29, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: @shopify/cli @shopify/cli package issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants