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: 3 additions & 2 deletions src/commands/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ const runDeploy = async ({
await prepareProductionDeploy({ siteData, api, options, command })
}

const draft = !deployToProduction && !alias
const draft = options.draft || (!deployToProduction && !alias)
const createDeployBody = { draft, branch: alias, include_upload_url: options.uploadSourceZip }

results = await api.createSiteDeploy({ siteId, title, body: createDeployBody })
Expand Down Expand Up @@ -1050,7 +1050,8 @@ export const deploy = async (options: DeployOptionValues, command: BaseCommand)
return triggerDeploy({ api, options, siteData, siteId })
}

const deployToProduction = options.prod || (options.prodIfUnlocked && !(siteData.published_deploy?.locked ?? false))
const deployToProduction =
!options.draft && (options.prod || (options.prodIfUnlocked && !(siteData.published_deploy?.locked ?? false)))

let results = {} as Awaited<ReturnType<typeof prepAndRunDeploy>>

Expand Down
10 changes: 8 additions & 2 deletions src/commands/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ For detailed configuration options, see the Netlify documentation.`,
.addOption(
new Option('-p, --prod', 'Deploy to production')
.default(false)
.conflicts(['alias', 'branch', 'prod-if-unlocked']),
.conflicts(['alias', 'branch', 'prod-if-unlocked', 'draft']),
)
.addOption(
new Option('--prod-if-unlocked', 'Deploy to production if unlocked, create a draft otherwise')
.default(false)
.conflicts(['alias', 'branch', 'prod']),
.conflicts(['alias', 'branch', 'prod', 'draft']),
)
.addOption(
new Option('--draft', 'Explicitly create a draft deploy')
.default(false)
.conflicts(['prod', 'prod-if-unlocked'])
.hideHelp(true),
)
.option(
'--alias <name>',
Expand Down
1 change: 1 addition & 0 deletions src/commands/deploy/option_values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type DeployOptionValues = BaseOptionValues & {
context?: string
createSite?: string | boolean
dir?: string
draft: boolean
functions?: string
json: boolean
message?: string
Expand Down
92 changes: 92 additions & 0 deletions tests/integration/commands/deploy/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,98 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co
})
})

test('should deploy as draft when --draft flag is used', async (t) => {
await withSiteBuilder(t, async (builder) => {
const content = '<h1>Draft deploy test</h1>'
builder.withContentFile({
path: 'public/index.html',
content,
})

await builder.build()

const deploy = await callCli(['deploy', '--json', '--no-build', '--dir', 'public', '--draft'], {
cwd: builder.directory,
env: { NETLIFY_SITE_ID: context.siteId },
}).then((output: string) => JSON.parse(output))

await validateDeploy({ deploy, siteName: SITE_NAME, content })
expect(deploy).toHaveProperty(
'function_logs',
`https://app.netlify.com/projects/${SITE_NAME}/logs/functions?scope=deploy:${deploy.deploy_id}`,
)
expect(deploy).toHaveProperty(
'edge_function_logs',
`https://app.netlify.com/projects/${SITE_NAME}/logs/edge-functions?scope=deployid:${deploy.deploy_id}`,
)
})
})

test('should not run deploy with --draft and --prod flags together', async (t) => {
await withSiteBuilder(t, async (builder) => {
await builder.build()
try {
await callCli(['deploy', '--no-build', '--draft', '--prod'], {
cwd: builder.directory,
env: { NETLIFY_SITE_ID: context.siteId },
})
} catch (error) {
expect(error).toHaveProperty(
'stderr',
expect.stringContaining(`Error: option '-p, --prod' cannot be used with option '--draft'`),
)
}
})
})

test('should not run deploy with --draft and --prod-if-unlocked flags together', async (t) => {
await withSiteBuilder(t, async (builder) => {
await builder.build()
try {
await callCli(['deploy', '--no-build', '--draft', '--prod-if-unlocked'], {
cwd: builder.directory,
env: { NETLIFY_SITE_ID: context.siteId },
})
} catch (error) {
expect(error).toHaveProperty(
'stderr',
expect.stringContaining(`Error: option '--prod-if-unlocked' cannot be used with option '--draft'`),
)
}
})
})

test('should deploy as draft when --draft flag is used with --alias and --no-build', async (t) => {
await withSiteBuilder(t, async (builder) => {
const content = '<h1>Draft deploy with alias test</h1>'
builder.withContentFile({
path: 'public/index.html',
content,
})

await builder.build()

const deploy = await callCli(
['deploy', '--json', '--no-build', '--dir', 'public', '--draft', '--alias', 'test-branch'],
{
cwd: builder.directory,
env: { NETLIFY_SITE_ID: context.siteId },
},
).then((output: string) => JSON.parse(output))

await validateDeploy({ deploy, siteName: SITE_NAME, content })
expect(deploy).toHaveProperty(
'function_logs',
`https://app.netlify.com/projects/${SITE_NAME}/logs/functions?scope=deploy:${deploy.deploy_id}`,
)
expect(deploy).toHaveProperty(
'edge_function_logs',
`https://app.netlify.com/projects/${SITE_NAME}/logs/edge-functions?scope=deployid:${deploy.deploy_id}`,
)
expect(deploy.deploy_url).toContain('test-branch--')
})
})

test('should include source_zip_filename in JSON output when --upload-source-zip flag is used', async (t) => {
await withSiteBuilder(t, async (builder) => {
const content = '<h1>Source zip test</h1>'
Expand Down