Skip to content

Add subscription migration list command - #8478

Open
tyler-eon wants to merge 6 commits into
mainfrom
eon/subscription-migrations-list
Open

Add subscription migration list command#8478
tyler-eon wants to merge 6 commits into
mainfrom
eon/subscription-migrations-list

Conversation

@tyler-eon

@tyler-eon tyler-eon commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

What this changes

Adds the subscription migration command:

shopify app subscription-migrations list

The command:

  • fetches every page from the new migratableAppSubscriptions Partners CLI GraphQL query;
  • optionally filters by UNSCHEDULED, SCHEDULED, or MIGRATED;
  • streams a comprehensive CSV to stdout by default;
  • streams one versioned JSON document to stdout with --json;
  • supports saving either format through normal shell redirection;

The read model can preserve historical NONE notification values returned by the API without re-enabling NONE as a schedule-input option.

Examples

shopify app subscription-migrations list
shopify app subscription-migrations list --status UNSCHEDULED
shopify app subscription-migrations list --json
shopify app subscription-migrations list > subscriptions.csv
shopify app subscription-migrations list --json > subscriptions.json

Verification

  • 22 focused test files: 251 passed, 1 platform-specific skip
  • App and CLI Kit type-checks
  • App, CLI, and CLI Kit builds
  • ESLint
  • Knip
  • Oclif manifest generation
  • Command snapshot validation
  • Direct hidden-command help and normal-discovery checks
  • CSV escaping, JSON schema, stdout purity, nullable API response, and cursor pagination coverage

Assisted-By: devx/0b604c20-c9ef-42f2-a0b6-f4cb3118b82f
Assisted-By: devx/0b604c20-c9ef-42f2-a0b6-f4cb3118b82f
Assisted-By: devx/0b604c20-c9ef-42f2-a0b6-f4cb3118b82f
Assisted-By: devx/0b604c20-c9ef-42f2-a0b6-f4cb3118b82f
Assisted-By: devx/0b604c20-c9ef-42f2-a0b6-f4cb3118b82f
@tyler-eon
tyler-eon requested review from a team as code owners September 4, 2026 15:57
@github-actions github-actions Bot added the no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. label Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

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

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/fs.d.ts
@@ -86,6 +86,7 @@ export declare function appendFile(path: string, content: string): Promise<void>
 export declare function appendFileSync(path: string, data: string): void;
 export interface WriteOptions {
     encoding: BufferEncoding;
+    flag?: 'w' | 'wx';
 }
 /**
  * Writes content to file at path.

...sharedFlags,
output: Flags.string({
description: 'Path to write the subscription export.',
env: 'SHOPIFY_FLAG_OUTPUT',

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.

UNIXey nit: Do we need --output / --force? Shouldn't folks just be able to run subscription migrations list > file.csv?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm going to remove --output and --force, but for CSV output specifically I'm also going to make it stream each page of results. If we're writing CSV data to stdout then we can stream each page without risking a malformed csv output, but with --json we can't safely do that. So CSV output can stream, JSON output won't for now just to avoid a failed invocation leaving behind a malformed JSON file.

Assisted-By: devx/0b604c20-c9ef-42f2-a0b6-f4cb3118b82f
// Pages must be requested sequentially because each request depends on the previous opaque cursor.
// eslint-disable-next-line no-await-in-loop
const page = await getPage({clientId, first: PAGE_SIZE, after, status})
if (page === null) throw new AbortError('App not found')

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.

Could this throw a domain-specific error and let List.run() translate it to AbortError? Throwing AbortError makes three CLI-specific choices: how to show the error, which exit status to use, and how to encode the JSON error. Ideally those choices belong at the command boundary rather than in the internal execution.

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

This LGTM from a code standpoint. My comments about output format are non-blocking, though my opinion is that we don't need so much code to handle output formatting when that's already handled well-enough by the OS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants