Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/keypress-accepted-keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/cli-kit': minor
---

`keypress` accepts a `keys` option: only those keys end the wait, and other keys are ignored. `keypress` now sets raw mode back to its earlier state, and it also detects Ctrl+C when an Ink renderer has set the stdin encoding.
7 changes: 7 additions & 0 deletions .changeset/theme-trust-challenge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@shopify/cli-kit': minor
'@shopify/theme': patch
'@shopify/app': patch
---

Handle Trust Battery identity challenges in theme commands. When Shopify asks you to verify your identity, the CLI opens the verification page in your browser and continues after you complete it. In CI, with `--no-input`, or with `--json`, the command stops and prints the verification link. `app dev` stops creating its host theme when you cancel the verification or it fails, instead of trying again.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {waitForThemeToBeProcessed} from './host-theme-watcher.js'
import {HostThemeManager, DEFAULT_THEME_ZIP, FALLBACK_THEME_ZIP} from './host-theme-manager.js'
import {themeCreate} from '@shopify/cli-kit/node/themes/api'
import {isTrustChallengeError, themeCreate} from '@shopify/cli-kit/node/themes/api'
import {AbortError, AbortSilentError} from '@shopify/cli-kit/node/error'
import {beforeEach, describe, expect, test, vi} from 'vitest'
import {DEVELOPMENT_THEME_ROLE} from '@shopify/cli-kit/node/themes/utils'
import {AdminSession} from '@shopify/cli-kit/node/session'
Expand Down Expand Up @@ -179,5 +180,45 @@ describe('HostThemeManager', () => {
)
expect(themeCreate).toHaveBeenCalledTimes(4)
})

test('stops retrying when the Trust Battery prompt is cancelled with Ctrl+C', async () => {
// Given
vi.mocked(themeCreate).mockRejectedValue(new AbortSilentError())

// When
// Then
await expect(themeManager.findOrCreate()).rejects.toBeInstanceOf(AbortSilentError)
expect(themeCreate).toHaveBeenCalledTimes(1)
})

test('stops retrying when a Trust Battery challenge ends the request', async () => {
// Given
const challengeError = new AbortError('Shopify still needs to verify your identity before it can continue.')
vi.mocked(themeCreate).mockRejectedValue(challengeError)
vi.mocked(isTrustChallengeError).mockImplementation((error) => error === challengeError)

// When
// Then
await expect(themeManager.findOrCreate()).rejects.toBe(challengeError)
expect(themeCreate).toHaveBeenCalledTimes(1)
})

test('keeps retrying a theme creation abort that is not a Trust Battery challenge', async () => {
// Given
vi.mocked(themeCreate).mockRejectedValueOnce(new AbortError('Source is empty')).mockResolvedValueOnce({
id: 12345,
name: 'Theme',
role: 'development',
createdAtRuntime: true,
processing: true,
})
vi.mocked(isTrustChallengeError).mockReturnValue(false)

// When
await themeManager.findOrCreate()

// Then
expect(themeCreate).toHaveBeenCalledTimes(2)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import {getHostTheme, removeHostTheme, setHostTheme} from '@shopify/cli-kit/node
import {ThemeManager} from '@shopify/cli-kit/node/themes/theme-manager'
import {AdminSession} from '@shopify/cli-kit/node/session'
import {Theme} from '@shopify/cli-kit/node/themes/types'
import {themeCreate} from '@shopify/cli-kit/node/themes/api'
import {isTrustChallengeError, themeCreate} from '@shopify/cli-kit/node/themes/api'
import {DEVELOPMENT_THEME_ROLE} from '@shopify/cli-kit/node/themes/utils'
import {BugError} from '@shopify/cli-kit/node/error'
import {AbortSilentError, BugError} from '@shopify/cli-kit/node/error'
import {outputDebug} from '@shopify/cli-kit/node/output'

export const DEFAULT_THEME_ZIP = 'https://codeload.github.com/Shopify/dawn/zip/refs/tags/v15.0.0'
Expand Down Expand Up @@ -60,8 +60,8 @@ export class HostThemeManager extends ThemeManager {
} else {
throw new Error()
}
// eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
if (error instanceof AbortSilentError || isTrustChallengeError(error)) throw error
outputDebug(`Failed to create theme with name "${options.name}" and role "${options.role}". Retrying...`)
}
}
Expand Down
Loading
Loading