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
92 changes: 92 additions & 0 deletions packages/app/src/cli/prompts/deploy-release.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,98 @@ describe('deployOrReleaseConfirmationPrompt', () => {
}),
).rejects.toThrow('This deployment includes changes that require confirmation.')
})

test('non-TTY with only updates should suggest --allow-updates flag in error', async () => {
// Given
const breakdownInfo = buildEmptyBreakdownInfo()
// Add only updates (no deletes)
breakdownInfo.extensionIdentifiersBreakdown.toCreate = [buildExtensionBreakdownInfo('new extension', 'uid-new')]
breakdownInfo.configExtensionIdentifiersBreakdown!.newFieldNames = ['new field']

vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {})
vi.spyOn(ui, 'isTTY').mockReturnValue(false)

// When/Then
await expect(
deployOrReleaseConfirmationPrompt({
...breakdownInfo,
appTitle: 'app title',
release: true,
force: false,
}),
).rejects.toMatchObject({
message: 'This deployment includes changes that require confirmation.',
// tryMessage contains the suggestion with the command token
tryMessage: expect.arrayContaining([{command: '--allow-updates'}]),
})
})

test('non-TTY with only deletes should suggest --allow-deletes flag in error', async () => {
// Given
const breakdownInfo = buildEmptyBreakdownInfo()
// Add only deletes (no updates)
breakdownInfo.extensionIdentifiersBreakdown.onlyRemote = [
buildExtensionBreakdownInfo('remote extension', 'uid-remote'),
]

vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {})
vi.spyOn(ui, 'isTTY').mockReturnValue(false)

// When/Then
await expect(
deployOrReleaseConfirmationPrompt({
...breakdownInfo,
appTitle: 'app title',
release: true,
force: false,
}),
).rejects.toMatchObject({
message: 'This deployment includes changes that require confirmation.',
// tryMessage contains the suggestion with the command token
tryMessage: expect.arrayContaining([{command: '--allow-deletes'}]),
})
})

test('non-TTY with both updates and deletes should suggest both flags in error', async () => {
// Given
const breakdownInfo = buildCompleteBreakdownInfo()
vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {})
vi.spyOn(ui, 'isTTY').mockReturnValue(false)

// When/Then
await expect(
deployOrReleaseConfirmationPrompt({
...breakdownInfo,
appTitle: 'app title',
release: true,
force: false,
}),
).rejects.toMatchObject({
message: 'This deployment includes changes that require confirmation.',
// tryMessage contains the suggestion with both command flags joined
tryMessage: expect.arrayContaining([{command: '--allow-updates --allow-deletes'}]),
})
})

test('non-TTY without any changes should not throw error', async () => {
// Given
const breakdownInfo = buildEmptyBreakdownInfo()
const renderConfirmationPromptSpyOn = vi.spyOn(ui, 'renderConfirmationPrompt').mockResolvedValue(true)
vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {})
vi.spyOn(ui, 'isTTY').mockReturnValue(false)

// When
const result = await deployOrReleaseConfirmationPrompt({
...breakdownInfo,
appTitle: 'app title',
release: true,
force: false,
})

// Then - should show the prompt normally since there are no changes requiring confirmation
expect(renderConfirmationPromptSpyOn).toHaveBeenCalled()
expect(result).toBe(true)
})
})
})

Expand Down
8 changes: 4 additions & 4 deletions packages/app/src/cli/prompts/deploy-release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ function shouldSkipConfirmationPrompt({

// If we're in non-TTY mode and there are changes that require confirmation, throw an error
if (!isTTY() && (hasDeletes || hasUpdates)) {
let suggestedFlag = '--force'
if (hasUpdates && !hasDeletes) suggestedFlag = '--allow-updates'
if (hasDeletes && !hasUpdates) suggestedFlag = '--allow-deletes'
const suggestedFlags: string[] = []
if (hasUpdates) suggestedFlags.push('--allow-updates')
if (hasDeletes) suggestedFlags.push('--allow-deletes')
throw new AbortError('This deployment includes changes that require confirmation.', [
'Run the command with',
{command: suggestedFlag},
{command: suggestedFlags.join(' ')},
'to deploy without confirmation.',
])
}
Expand Down
Loading