Skip to content

Commit 7310e1a

Browse files
committed
feat: improve cli
1 parent 4bd5fdf commit 7310e1a

File tree

5 files changed

+130
-31
lines changed

5 files changed

+130
-31
lines changed

cli/commands/deploy.mjs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { consola } from 'consola'
2+
import { colors } from 'consola/utils'
3+
import { isCancel, confirm, select, text } from '@clack/prompts'
4+
import { defineCommand, runCommand } from 'citty'
5+
import { loadConfig } from '../utils.mjs'
6+
import { $api } from '../utils.mjs'
7+
import login from './login.mjs'
8+
import { homedir } from 'os'
9+
10+
export default defineCommand({
11+
meta: {
12+
name: 'deploy',
13+
description: 'Deploy your project to NuxtHub.',
14+
},
15+
async setup() {
16+
const config = loadConfig()
17+
if (!config.token) {
18+
consola.info('You need to be logged in to deploy your project.')
19+
const res = await runCommand(login, {})
20+
console.log('res', res)
21+
}
22+
const shouldDeploy = await confirm({
23+
message: `Deploy ${colors.blue(process.cwd().replace(homedir(), '~'))} to NuxtHub?`
24+
})
25+
if (!shouldDeploy || isCancel(shouldDeploy)) {
26+
return consola.log('Cancelled.')
27+
}
28+
29+
const teams = await $api('/teams')
30+
const teamId = await select({
31+
message: 'Select a team',
32+
options: teams.map((team) => ({
33+
value: team.id,
34+
label: team.name
35+
}))
36+
})
37+
if (isCancel(teamId)) return
38+
const team = teams.find((team) => team.id === teamId)
39+
40+
const projects = await $api(`/teams/${team.slug}/projects`)
41+
const projectId = await select({
42+
message: 'Link a project',
43+
options: [
44+
{ value: 'new', label: 'Create a new project' },
45+
...projects.map((project) => ({
46+
value: project.id,
47+
label: project.slug
48+
}))
49+
]
50+
})
51+
if (isCancel(projectId)) return
52+
53+
let project
54+
if (projectId === 'new') {
55+
const projectName = await text({
56+
message: 'Project name',
57+
placeholder: 'my-nuxt-project'
58+
})
59+
if (isCancel(projectName)) return
60+
project = await $api(`/teams/${team.slug}/projects`, {
61+
method: 'POST',
62+
body: { name: projectName }
63+
})
64+
consola.success(`Project \`${project.slug}\` created`)
65+
} else {
66+
project = projects.find((project) => project.id === projectId)
67+
}
68+
69+
consola.info(`Deploying \`${project.slug}\` to NuxtHub...`)
70+
},
71+
})

cli/commands/login.mjs

+36-31
Original file line numberDiff line numberDiff line change
@@ -25,43 +25,48 @@ export default defineCommand({
2525
}
2626
// Create server for OAuth flow
2727
let listener
28-
const stopListener = () => setTimeout(() => listener.close(), 1000)
2928
const app = createApp()
3029
let handled = false
31-
app.use('/', eventHandler(async (event) => {
32-
if (handled) return
33-
handled = true
34-
const token = getQuery(event).token
30+
// eslint-disable-next-line no-async-promise-executor
31+
await new Promise(async (resolve, reject) => {
32+
app.use('/', eventHandler(async (event) => {
33+
if (handled) return
34+
handled = true
35+
const token = getQuery(event).token
3536

36-
if (token) {
37-
const user = await $api('/user', {
38-
headers: {
39-
Authorization: `token ${token}`
40-
}
41-
}).catch(() => null)
42-
if (user?.name) {
43-
writeConfig({ token })
44-
consola.success('Authenticated successfully!')
37+
if (token) {
38+
const user = await $api('/user', {
39+
headers: {
40+
Authorization: `token ${token}`
41+
}
42+
}).catch(() => null)
43+
if (user?.name) {
44+
writeConfig({ token })
45+
consola.success('Authenticated successfully!')
4546

46-
stopListener()
47+
resolve()
4748

48-
// TODO: redirect to success CLI page: https://hub.nuxt.com/cli/login-success?name=${user.name}
49-
return 'Authenticated successfully! You can close this window now.'
49+
// TODO: redirect to success CLI page: https://hub.nuxt.com/cli/login-success?name=${user.name}
50+
return 'Authenticated successfully! You can close this window now.'
51+
}
5052
}
51-
}
52-
consola.error('Authentication error, please try again.')
53-
stopListener()
54-
return 'Authentication error, missing token.'
55-
}))
56-
const randomPort = await getRandomPort()
57-
listener = await listen(toNodeListener(app), {
58-
showURL: false,
59-
port: randomPort
53+
consola.error('Authentication error, please try again.')
54+
reject()
55+
return 'Authentication error, missing token.'
56+
}))
57+
const randomPort = await getRandomPort()
58+
listener = await listen(toNodeListener(app), {
59+
showURL: false,
60+
port: randomPort
61+
})
62+
consola.box(
63+
'Please visit the following URL in your web browser:\n\n'+
64+
'`'+withQuery(joinURL(NUXT_HUB_URL, '/api/cli/authorize'), { redirect: listener.url })+'`'
65+
)
66+
consola.info('Waiting for authentication to be completed...')
6067
})
61-
consola.box(
62-
'Please visit the following URL in your web browser:\n\n'+
63-
withQuery(joinURL(NUXT_HUB_URL, '/api/cli/authorize'), { redirect: listener.url })
64-
)
65-
consola.info('Waiting for authentication to be completed...')
68+
// Close server after 1s to make sure we have time to handle the request
69+
await new Promise((resolve) => setTimeout(resolve, 1000))
70+
await listener.close()
6671
},
6772
})

cli/index.mjs

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { colors } from 'consola/utils'
55
import login from './commands/login.mjs'
66
import logout from './commands/logout.mjs'
77
import whoami from './commands/whoami.mjs'
8+
import deploy from './commands/deploy.mjs'
89

910
const main = defineCommand({
1011
meta: {
@@ -17,6 +18,7 @@ const main = defineCommand({
1718
}
1819
},
1920
subCommands: {
21+
deploy,
2022
login,
2123
logout,
2224
whoami

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"release": "release-it"
3030
},
3131
"dependencies": {
32+
"@clack/prompts": "^0.7.0",
3233
"@cloudflare/workers-types": "^4.20240208.0",
3334
"@sindresorhus/slugify": "^2.2.1",
3435
"@uploadthing/mime-types": "^0.2.2",

pnpm-lock.yaml

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)