cli icon indicating copy to clipboard operation
cli copied to clipboard

Add resilliency to errors on concurrent build asset writes

Open alfonso-noriega opened this issue 1 month ago β€’ 8 comments

WHY are these changes introduced?

Fixes an issue where the extension bundling process would fail completely if any single file couldn't be copied, preventing developers from continuing their work.

WHAT is this pull request doing?

Improves error handling during extension bundling by:

  • Using Promise.allSettled() instead of Promise.all() to prevent the entire process from failing if a single file copy fails
  • Adding detailed error reporting for failed file copies
  • Outputting debug warnings when files can't be copied instead of crashing
  • Continuing the bundling process even when some files fail to copy

How to test your changes?

  1. Create a theme or UI extension with a file that can't be copied (e.g., a file with special permissions or a locked file)
  2. Run shopify app dev
  3. Verify that the build process completes successfully despite the problematic file
  4. Check the debug output for warnings about files that couldn't be copied

Measuring impact

How do we know this change was effective? Please choose one:

  • [x] n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix

Checklist

  • [x] I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • [x] I've considered possible documentation changes

alfonso-noriega avatar Oct 31 '25 12:10 alfonso-noriega

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

alfonso-noriega avatar Oct 31 '25 12:10 alfonso-noriega

Coverage report

St.:grey_question:
Category Percentage Covered / Total
🟑 Statements
79.25% (+0.03% πŸ”Ό)
13609/17172
🟑 Branches
73.14% (+0.09% πŸ”Ό)
6654/9097
🟑 Functions
79.35% (+0.07% πŸ”Ό)
3508/4421
🟑 Lines
79.61% (+0.02% πŸ”Ό)
12854/16146
Show new covered files 🐣
St.:grey_question:
File Statements Branches Functions Lines
πŸ”΄
... / info.ts
0% 0% 0% 0%
🟒
... / info.ts
100% 87.5% 100% 100%
Show files with reduced coverage πŸ”»
St.:grey_question:
File Statements Branches Functions Lines
🟒
... / loader.ts
93.86% (+0.74% πŸ”Ό)
86.7% (+1.06% πŸ”Ό)
97.06% (-0.03% πŸ”»)
94.67% (+0.53% πŸ”Ό)
🟒
... / ui_extension.ts
94.83% (+0.04% πŸ”Ό)
81.25% (-1.64% πŸ”»)
100%
96.46% (+0.03% πŸ”Ό)
🟒
... / Dev.tsx
90.59% (-2.35% πŸ”»)
75% (-1.79% πŸ”»)
86.36% (-4.55% πŸ”»)
92.5% (-1.25% πŸ”»)
🟒
... / bundle.ts
83.82% (-9.4% πŸ”»)
65.71% (-0.95% πŸ”»)
84.21% (-4.02% πŸ”»)
85.71% (-10.58% πŸ”»)
🟒
... / git.ts
93.16% (+0.78% πŸ”Ό)
87.93% (-1.35% πŸ”»)
90.91% (+0.43% πŸ”Ό)
94.34% (+1.2% πŸ”Ό)
🟑
... / admin.ts
72.22% (-2.78% πŸ”»)
40% (-5.16% πŸ”»)
90.91%
73.58% (-2.89% πŸ”»)
πŸ”΄
... / dev.ts
13.04% (-0.29% πŸ”»)
2.94% 57.14%
13.04% (-0.29% πŸ”»)
🟒
... / theme-uploader.ts
91.84% (+0.12% πŸ”Ό)
78.21% (-0.83% πŸ”»)
86.36% (-1.14% πŸ”»)
93.18% (+0.59% πŸ”Ό)
🟑
... / theme-environment.ts
70.45% (-0.97% πŸ”»)
50%
57.89% (-0.93% πŸ”»)
70.45% (-0.97% πŸ”»)

Test suite run success

3358 tests passing in 1372 suites.

Report generated by πŸ§ͺjest coverage report action from b49c429baa4b68bebbc01bb1822ff342ecd17ad2

github-actions[bot] avatar Oct 31 '25 12:10 github-actions[bot]

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[bot] avatar Oct 31 '25 13:10 github-actions[bot]

/snapit

isaacroldan avatar Nov 03 '25 12:11 isaacroldan

🫰✨ Thanks @isaacroldan! 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.

github-actions[bot] avatar Nov 03 '25 12:11 github-actions[bot]

when you have automatic build from an external vite running in parallel with dev which is, with every change that you do, deleting the assets folder and rewriting it, it may happend that you delete something that is listed in glob to be copied

alfonso-noriega avatar Nov 04 '25 15:11 alfonso-noriega

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/private/node/analytics.d.ts
@@ -27,6 +27,5 @@ interface EnvironmentData {
 export declare function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData>;
 export declare function getSensitiveEnvironmentData(config: Interfaces.Config): Promise<{
     env_plugin_installed_all: string;
-    env_shopify_variables: string;
 }>;
 export {};
\ No newline at end of file

packages/cli-kit/dist/private/node/api.d.ts
@@ -11,30 +11,6 @@ type RequestOptions<T> = {
     request: () => Promise<T>;
     url: string;
 } & NetworkRetryBehaviour;
-/**
- * Checks if an error is a transient network error that is likely to recover with retries.
- *
- * Use this function for retry logic. Use isNetworkError for error classification.
- *
- * Examples of transient errors (worth retrying):
- * - Connection timeouts, resets, and aborts
- * - DNS failures (enotfound, getaddrinfo, eai_again) - can be temporary
- * - Socket disconnects and hang ups
- * - Premature connection closes
- */
-export declare function isTransientNetworkError(error: unknown): boolean;
-/**
- * Checks if an error is any kind of network-related error (connection issues, timeouts, DNS failures,
- * TLS/certificate errors, etc.) rather than an application logic error.
- *
- * These errors should be reported as user-facing errors (AbortError) rather than bugs (BugError),
- * regardless of whether they are transient or permanent.
- *
- * Examples include:
- * - Transient: connection timeouts, socket hang ups, temporary DNS failures
- * - Permanent: certificate validation failures, misconfigured SSL
- */
-export declare function isNetworkError(error: unknown): boolean;
 export declare function simpleRequestWithDebugLog<T extends {
     headers: Headers;
     status: number;

packages/cli-kit/dist/public/node/metadata.d.ts
@@ -55,7 +55,6 @@ declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
     cmd_all_environment_flags?: string | null;
     cmd_dev_tunnel_custom?: string | null;
     env_plugin_installed_all?: string | null;
-    env_shopify_variables?: string | null;
 }, "store_", never>>;
 export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>, getAllSensitiveMetadata: () => Partial<{
     commandStartOptions: {
@@ -75,7 +74,6 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
     cmd_all_environment_flags?: string | null;
     cmd_dev_tunnel_custom?: string | null;
     env_plugin_installed_all?: string | null;
-    env_shopify_variables?: string | null;
 }, "store_", never>>, addPublicMetadata: (getData: ProvideMetadata<CmdFieldsFromMonorail>, onError?: MetadataErrorHandling) => Promise<void>, addSensitiveMetadata: (getData: ProvideMetadata<{
     commandStartOptions: {
         startTime: number;
@@ -94,7 +92,6 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
     cmd_all_environment_flags?: string | null;
     cmd_dev_tunnel_custom?: string | null;
     env_plugin_installed_all?: string | null;
-    env_shopify_variables?: string | null;
 }, "store_", never>>, onError?: MetadataErrorHandling) => Promise<void>, runWithTimer: (field: NumericKeyOf<CmdFieldsFromMonorail>) => <T>(fn: () => Promise<T>) => Promise<T>;
 export type Public = PublicSchema<typeof coreData>;
 export type Sensitive = SensitiveSchema<typeof coreData>;

packages/cli-kit/dist/public/node/monorail.d.ts
@@ -2,7 +2,7 @@ import { JsonMap } from '../../private/common/json.js';
 import { DeepRequired } from '../common/ts/deep-required.js';
 export { DeepRequired };
 type Optional<T> = T | null;
-export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.20";
+export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.19";
 export interface Schemas {
     [MONORAIL_COMMAND_TOPIC]: {
         sensitive: {
@@ -14,7 +14,6 @@ export interface Schemas {
             cmd_all_environment_flags?: Optional<string>;
             cmd_dev_tunnel_custom?: Optional<string>;
             env_plugin_installed_all?: Optional<string>;
-            env_shopify_variables?: Optional<string>;
         };
         public: {
             business_platform_id?: Optional<number>;

packages/cli-kit/dist/cli/api/graphql/admin/generated/theme_files_upsert.d.ts
@@ -8,7 +8,6 @@ export type ThemeFilesUpsertMutation = {
     themeFilesUpsert?: {
         upsertedThemeFiles?: {
             filename: string;
-            checksumMd5?: string | null;
         }[] | null;
         userErrors: {
             filename?: string | null;

github-actions[bot] avatar Nov 05 '25 09:11 github-actions[bot]

@alfonso-noriega I think @gonzaloriestra is right, because this method is also used during deploy so we need to handle errors better

isaacroldan avatar Nov 05 '25 09:11 isaacroldan