Skip to content

Add app:dev:clean command to stop app previews #5648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions packages/app/src/cli/commands/app/dev/clean.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {linkedAppContext} from '../../../services/app-context.js'
import AppCommand, {AppCommandOutput} from '../../../utilities/app-command.js'
import {appFlags} from '../../../flags.js'
import {storeContext} from '../../../services/store-context.js'
import {globalFlags} from '@shopify/cli-kit/node/cli'
import {Flags} from '@oclif/core'
import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn'
import {renderSuccess} from '@shopify/cli-kit/node/ui'

export default class DevClean extends AppCommand {
static summary = 'Cleans up the app preview from the selected store.'

static descriptionWithMarkdown = `Stop the app preview that was started with \`shopify app dev\`.

It restores the app's active version to the selected development store.
`

static description = this.descriptionWithoutMarkdown()

static hidden = true

static flags = {
...globalFlags,
...appFlags,
store: Flags.string({
hidden: false,
char: 's',
description: 'Store URL. Must be an existing development store.',
env: 'SHOPIFY_FLAG_STORE',
parse: async (input) => normalizeStoreFqdn(input),
}),
}

public async run(): Promise<AppCommandOutput> {
const {flags} = await this.parse(DevClean)

const appContextResult = await linkedAppContext({
directory: flags.path,
clientId: flags['client-id'],
forceRelink: flags.reset,
userProvidedConfigName: flags.config,
})

const store = await storeContext({
appContextResult,
storeFqdn: flags.store,
forceReselectStore: flags.reset,
})

const client = appContextResult.developerPlatformClient
await client.devSessionDelete({shopFqdn: store.shopDomain, appId: appContextResult.remoteApp.id})

renderSuccess({
headline: 'App preview stopped.',
body: [
`The app preview has been stopped on "${store.shopDomain}" and the app's active version has been restored.`,
'You can start it again with `shopify app dev`.',
],
})

return {app: appContextResult.app}
}
}
2 changes: 2 additions & 0 deletions packages/app/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import init from './hooks/clear_command_cache.js'
import gatherPublicMetadata from './hooks/public_metadata.js'
import gatherSensitiveMetadata from './hooks/sensitive_metadata.js'
import AppCommand from './utilities/app-command.js'
import DevClean from './commands/app/dev/clean.js'

/**
* All app commands should extend AppCommand.
Expand All @@ -34,6 +35,7 @@ export const commands: {[key: string]: typeof AppCommand} = {
'app:build': Build,
'app:deploy': Deploy,
'app:dev': Dev,
'app:dev:clean': DevClean,
'app:logs': Logs,
'app:logs:sources': Sources,
'app:import-extensions': ImportExtensions,
Expand Down
89 changes: 89 additions & 0 deletions packages/cli/oclif.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,95 @@
"strict": true,
"summary": "Run the app."
},
"app:dev:clean": {
"aliases": [
],
"args": {
},
"customPluginName": "@shopify/app",
"description": "Stop the app preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ",
"descriptionWithMarkdown": "Stop the app preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ",
"flags": {
"client-id": {
"description": "The Client ID of your app.",
"env": "SHOPIFY_FLAG_CLIENT_ID",
"exclusive": [
"config"
],
"hasDynamicHelp": false,
"hidden": false,
"multiple": false,
"name": "client-id",
"type": "option"
},
"config": {
"char": "c",
"description": "The name of the app configuration.",
"env": "SHOPIFY_FLAG_APP_CONFIG",
"hasDynamicHelp": false,
"hidden": false,
"multiple": false,
"name": "config",
"type": "option"
},
"no-color": {
"allowNo": false,
"description": "Disable color output.",
"env": "SHOPIFY_FLAG_NO_COLOR",
"hidden": false,
"name": "no-color",
"type": "boolean"
},
"path": {
"description": "The path to your app directory.",
"env": "SHOPIFY_FLAG_PATH",
"hasDynamicHelp": false,
"multiple": false,
"name": "path",
"noCacheDefault": true,
"type": "option"
},
"reset": {
"allowNo": false,
"description": "Reset all your settings.",
"env": "SHOPIFY_FLAG_RESET",
"exclusive": [
"config"
],
"hidden": false,
"name": "reset",
"type": "boolean"
},
"store": {
"char": "s",
"description": "Store URL. Must be an existing development store.",
"env": "SHOPIFY_FLAG_STORE",
"hasDynamicHelp": false,
"hidden": false,
"multiple": false,
"name": "store",
"type": "option"
},
"verbose": {
"allowNo": false,
"description": "Increase the verbosity of the output.",
"env": "SHOPIFY_FLAG_VERBOSE",
"hidden": false,
"name": "verbose",
"type": "boolean"
}
},
"hasDynamicHelp": false,
"hidden": true,
"hiddenAliases": [
],
"id": "app:dev:clean",
"pluginAlias": "@shopify/cli",
"pluginName": "@shopify/cli",
"pluginType": "core",
"strict": true,
"summary": "Cleans up the app preview from the selected store."
},
"app:env:pull": {
"aliases": [
],
Expand Down