Skip to content
Merged
1 change: 1 addition & 0 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"@shopify/theme-check-node": "3.27.0",
"@shopify/toml-patch": "0.3.0",
"chokidar": "3.6.0",
"csv-parse": "7.0.2",
"diff": "5.2.2",
"esbuild": "0.28.1",
"graphql-request": "6.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export type Scalars = {
BusinessUserID: { input: any; output: any; }
/** The ID for a BusinessUsersImport. */
BusinessUsersImportID: { input: any; output: any; }
/** The ID for a CollaboratorRelationship. */
CollaboratorRelationshipID: { input: any; output: any; }
/** A signed decimal number, which supports arbitrary precision and is serialized as a string. */
Decimal: { input: any; output: any; }
/** The ID for a DocumentAttachment. */
Expand All @@ -49,6 +51,11 @@ export type Scalars = {
JSON: { input: JsonMapType | string; output: JsonMapType; }
/** The ID for a LegalEntity. */
LegalEntityID: { input: any; output: any; }
/**
* An ISO 8601 date and time serialized with microsecond precision, so a value read
* from a field can be supplied back as an argument and still compare equal to the stored row.
*/
MicrosecondDateTime: { input: any; output: any; }
/** The ID for a OrganizationDomain. */
OrganizationDomainID: { input: any; output: any; }
/** The ID for a Organization. */
Expand All @@ -71,6 +78,8 @@ export type Scalars = {
RoleID: { input: any; output: any; }
/** The ID for a Shop. */
ShopID: { input: any; output: any; }
/** The ID for a ShopTransferRequest. */
ShopTransferRequestID: { input: any; output: any; }
/** The ID for a ShopifyShop. */
ShopifyShopID: { input: any; output: any; }
/** The ID for a StoreAdditionRequest. */
Expand Down
71 changes: 71 additions & 0 deletions packages/app/src/cli/api/graphql/subscription_migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {gql} from 'graphql-request'

// 250 matches the maximum migration submission batch size; operation results are currently bounded by that contract.
// eslint-disable-next-line @shopify/cli/no-inline-graphql
export const AppSubscriptionMigrationOperationCreateMutation = gql`
mutation AppSubscriptionMigrationOperationCreate($input: AppSubscriptionMigrationOperationCreateInput!) {
appSubscriptionMigrationOperationCreate(input: $input) {
operation {
id
status
total
results(first: 250) {
edges {
node {
shopId
code
}
}
}
}
userErrors {
message
field
}
}
}
`

// eslint-disable-next-line @shopify/cli/no-inline-graphql
export const AppSubscriptionMigrationOperationQuery = gql`
query AppSubscriptionMigrationOperation($apiKey: String!, $id: ID!) {
appSubscriptionMigrationOperation(apiKey: $apiKey, id: $id) {
id
status
total
results(first: 250) {
edges {
node {
shopId
code
}
}
}
}
}
`

// eslint-disable-next-line @shopify/cli/no-inline-graphql
export const AppSubscriptionMigrationOperationCancelMutation = gql`
mutation AppSubscriptionMigrationOperationCancel($input: AppSubscriptionMigrationOperationCancelInput!) {
appSubscriptionMigrationOperationCancel(input: $input) {
operation {
id
status
total
results(first: 250) {
edges {
node {
shopId
code
}
}
}
}
userErrors {
message
field
}
}
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {operationFlags} from './flags.js'
import {presentMigrationCancellationResult} from './result-presenter.js'
import {linkedAppContext} from '../../../services/app-context.js'
import {cancelMigrationOperations} from '../../../services/subscription-migrations/cancel-operations.js'
import AppLinkedCommand, {AppLinkedCommandOutput} from '../../../utilities/app-linked-command.js'

export default class Cancel extends AppLinkedCommand {
static hidden = true
static summary = 'Cancels app subscription migration operations.'

static descriptionWithMarkdown = `Cancels app subscription migration operations.

Canceling stops additional unprocessed shops, but does not undo shops that have already been scheduled or migrated. Use \`unschedule\` for reversible schedules.

Repeat \`--id\` to cancel every operation GID returned by a multi-batch submission. Use \`--json\` to output the resulting operation states and per-shop results as structured JSON.

Run the command from an app project. By default, it uses the Client ID from the active app configuration. Use \`--path\` to select an app directory or \`--config\` to select a configuration. Pass \`--client-id\` to select a different app within the project. Use \`--reset\` to relink the app.`

static description = this.descriptionWithoutMarkdown()

static examples = [
'<%= config.bin %> <%= command.id %> --id <operation-id>',
'<%= config.bin %> <%= command.id %> --path ../my-app --config staging --id <operation-id-1> --id <operation-id-2>',
'<%= config.bin %> <%= command.id %> --client-id <client-id> --id <operation-id> --json',
]

static flags = {...operationFlags}

async run(): Promise<AppLinkedCommandOutput> {
const {flags} = await this.parse(Cancel)
const {app, remoteApp} = await linkedAppContext({
directory: flags.path,
clientId: flags['client-id'],
forceRelink: flags.reset,
userProvidedConfigName: flags.config,
})
const result = await cancelMigrationOperations({
clientId: remoteApp.apiKey,
operationIds: flags.id,
})
const exitCode = presentMigrationCancellationResult(result, {json: flags.json})
if (exitCode !== 0) process.exitCode = exitCode
return {app}
}
}
Loading
Loading