mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
improve link command (#10257)
This commit is contained in:
parent
3df811a3bd
commit
2ecead463d
1 changed files with 186 additions and 36 deletions
|
@ -1,36 +1,60 @@
|
|||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import type { AstroConfig } from 'astro';
|
||||
import { slug } from 'github-slugger';
|
||||
import { bgRed, cyan } from 'kleur/colors';
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { homedir } from 'node:os';
|
||||
import { basename } from 'node:path';
|
||||
import ora from 'ora';
|
||||
import prompts from 'prompts';
|
||||
import type { Arguments } from 'yargs-parser';
|
||||
import { MISSING_SESSION_ID_ERROR } from '../../../errors.js';
|
||||
import { PROJECT_ID_FILE, getSessionIdFromFile } from '../../../tokens.js';
|
||||
import { getAstroStudioUrl } from '../../../utils.js';
|
||||
|
||||
export async function cmd({ flags }: { config: AstroConfig; flags: Arguments }) {
|
||||
const linkUrl = new URL(getAstroStudioUrl() + '/auth/cli/link');
|
||||
export async function cmd({}: { config: AstroConfig; flags: Arguments }) {
|
||||
const sessionToken = await getSessionIdFromFile();
|
||||
if (!sessionToken) {
|
||||
console.error(MISSING_SESSION_ID_ERROR);
|
||||
process.exit(1);
|
||||
}
|
||||
let body = { id: flags._[4] } as {
|
||||
id?: string;
|
||||
projectIdName?: string;
|
||||
workspaceIdName?: string;
|
||||
};
|
||||
if (!body.id) {
|
||||
const workspaceIdName = await promptWorkspaceName();
|
||||
const projectIdName = await promptProjectName();
|
||||
body = { projectIdName, workspaceIdName };
|
||||
const getWorkspaceIdAsync = getWorkspaceId();
|
||||
await promptBegin();
|
||||
const isLinkExisting = await promptLinkExisting();
|
||||
if (isLinkExisting) {
|
||||
const workspaceId = await getWorkspaceIdAsync;
|
||||
const existingProjectData = await promptExistingProjectName({workspaceId});
|
||||
return await linkProject(existingProjectData.id);
|
||||
}
|
||||
|
||||
const isLinkNew = await promptLinkNew();
|
||||
if (isLinkNew) {
|
||||
const workspaceId = await getWorkspaceIdAsync;
|
||||
const newProjectName = await promptNewProjectName();
|
||||
const newProjectRegion = await promptNewProjectRegion();
|
||||
const spinner = ora('Creating new project...').start();
|
||||
const newProjectData = await createNewProject({workspaceId, name: newProjectName, region: newProjectRegion});
|
||||
// TODO(fks): Actually listen for project creation before continuing
|
||||
// This is just a dumb spinner that roughly matches database creation time.
|
||||
await new Promise((r) => setTimeout(r, 4000));
|
||||
spinner.succeed('Project created!');
|
||||
return await linkProject(newProjectData.id);
|
||||
}
|
||||
}
|
||||
|
||||
async function linkProject(id: string) {
|
||||
await mkdir(new URL('.', PROJECT_ID_FILE), { recursive: true });
|
||||
await writeFile(PROJECT_ID_FILE, `${id}`);
|
||||
console.info('Project linked.');
|
||||
}
|
||||
|
||||
async function getWorkspaceId(): Promise<string> {
|
||||
const linkUrl = new URL(getAstroStudioUrl() + '/api/cli/workspaces.list');
|
||||
const response = await fetch(linkUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (!response.ok) {
|
||||
// Unauthorized
|
||||
|
@ -42,38 +66,164 @@ export async function cmd({ flags }: { config: AstroConfig; flags: Arguments })
|
|||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.error(`Failed to link project: ${response.status} ${response.statusText}`);
|
||||
console.error(`Failed to fetch user workspace: ${response.status} ${response.statusText}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const { data } = await response.json();
|
||||
await mkdir(new URL('.', PROJECT_ID_FILE), { recursive: true });
|
||||
await writeFile(PROJECT_ID_FILE, `${data.id}`);
|
||||
console.info('Project linked.');
|
||||
const { data, success } = await response.json() as {success: false, data: unknown} | {success: true, data: {id: string}[]};
|
||||
if (!success) {
|
||||
console.error(`Failed to fetch user's workspace.`);
|
||||
process.exit(1);
|
||||
}
|
||||
return data[0].id;
|
||||
}
|
||||
|
||||
export async function promptProjectName(defaultName?: string): Promise<string> {
|
||||
const { projectName } = await prompts({
|
||||
type: 'text',
|
||||
name: 'projectName',
|
||||
message: 'Project ID',
|
||||
initial: defaultName,
|
||||
export async function createNewProject({workspaceId, name, region}: {workspaceId: string; name: string, region: string}) {
|
||||
const linkUrl = new URL(getAstroStudioUrl() + '/api/cli/projects.create');
|
||||
const response = await fetch(linkUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ workspaceId, name, region }),
|
||||
});
|
||||
if (typeof projectName !== 'string') {
|
||||
process.exit(0);
|
||||
if (!response.ok) {
|
||||
// Unauthorized
|
||||
if (response.status === 401) {
|
||||
console.error(
|
||||
`${bgRed('Unauthorized')}\n\n Are you logged in?\n Run ${cyan(
|
||||
'astro db login'
|
||||
)} to authenticate and then try linking again.\n\n`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
console.error(`Failed to create project: ${response.status} ${response.statusText}`);
|
||||
process.exit(1);
|
||||
}
|
||||
return projectName;
|
||||
const { data, success } = await response.json() as {success: false, data: unknown} | {success: true, data: {id: string; idName: string}};
|
||||
if (!success) {
|
||||
console.error(`Failed to create project.`);
|
||||
process.exit(1);
|
||||
}
|
||||
return {id: data.id, idName: data.idName};
|
||||
}
|
||||
|
||||
export async function promptWorkspaceName(defaultName?: string): Promise<string> {
|
||||
const { workspaceName } = await prompts({
|
||||
type: 'text',
|
||||
name: 'workspaceName',
|
||||
message: 'Workspace ID',
|
||||
initial: defaultName,
|
||||
export async function promptExistingProjectName({workspaceId}: {workspaceId: string}) {
|
||||
const linkUrl = new URL(getAstroStudioUrl() + '/api/cli/projects.list');
|
||||
const response = await fetch(linkUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({workspaceId}),
|
||||
});
|
||||
if (typeof workspaceName !== 'string') {
|
||||
if (!response.ok) {
|
||||
// Unauthorized
|
||||
if (response.status === 401) {
|
||||
console.error(
|
||||
`${bgRed('Unauthorized')}\n\n Are you logged in?\n Run ${cyan(
|
||||
'astro db login'
|
||||
)} to authenticate and then try linking again.\n\n`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
console.error(`Failed to fetch projects: ${response.status} ${response.statusText}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const { data, success } = await response.json() as {success: false, data: unknown} | {success: true, data: {id: string; idName: string}[]};
|
||||
if (!success) {
|
||||
console.error(`Failed to fetch projects.`);
|
||||
process.exit(1);
|
||||
}
|
||||
const { projectId } = await prompts({
|
||||
type: 'autocomplete',
|
||||
name: 'projectId',
|
||||
message: 'What is your project name?',
|
||||
limit: 5,
|
||||
choices: data.map((p: any) => ({title: p.name, value: p.id})),
|
||||
});
|
||||
if (typeof projectId !== 'string') {
|
||||
console.log('Canceled.')
|
||||
process.exit(0);
|
||||
}
|
||||
return workspaceName;
|
||||
const selectedProjectData = data.find((p: any) => p.id === projectId)!;
|
||||
return selectedProjectData;
|
||||
}
|
||||
|
||||
export async function promptBegin(): Promise<void> {
|
||||
// Get the current working directory relative to the user's home directory
|
||||
const prettyCwd = process.cwd().replace(homedir(), '~');
|
||||
|
||||
// prompt
|
||||
const { begin } = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'begin',
|
||||
message: `Link "${prettyCwd}" with Astro Studio?`,
|
||||
initial: true,
|
||||
});
|
||||
if (!begin) {
|
||||
console.log('Canceled.')
|
||||
process.exit(0);
|
||||
};
|
||||
}
|
||||
|
||||
export async function promptLinkExisting(): Promise<boolean> {
|
||||
// prompt
|
||||
const { linkExisting } = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'linkExisting',
|
||||
message: `Link with an existing project in Astro Studio?`,
|
||||
initial: true,
|
||||
});
|
||||
return !!linkExisting;
|
||||
}
|
||||
|
||||
export async function promptLinkNew(): Promise<boolean> {
|
||||
// prompt
|
||||
const { linkNew } = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'linkNew',
|
||||
message: `Create a new project in Astro Studio?`,
|
||||
initial: true,
|
||||
});
|
||||
if (!linkNew) {
|
||||
console.log('Canceled.')
|
||||
process.exit(0);
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
export async function promptNewProjectName(): Promise<string> {
|
||||
const { newProjectName } = await prompts({
|
||||
type: 'text',
|
||||
name: 'newProjectName',
|
||||
message: `What is your new project's name?`,
|
||||
initial: basename(process.cwd()),
|
||||
format: (val) => slug(val),
|
||||
});
|
||||
if (!newProjectName) {
|
||||
console.log('Canceled.')
|
||||
process.exit(0);
|
||||
};
|
||||
return newProjectName;
|
||||
}
|
||||
|
||||
export async function promptNewProjectRegion(): Promise<string> {
|
||||
const { newProjectRegion } = await prompts({
|
||||
type: 'select',
|
||||
name: 'newProjectRegion',
|
||||
message: `Where should your new database live?`,
|
||||
choices: [
|
||||
{title: 'North America (East)', value: 'NorthAmericaEast'},
|
||||
{title: 'North America (West)', value: 'NorthAmericaWest'}
|
||||
],
|
||||
initial: 0,
|
||||
});
|
||||
if (!newProjectRegion) {
|
||||
console.log('Canceled.')
|
||||
process.exit(0);
|
||||
};
|
||||
return newProjectRegion;
|
||||
}
|
Loading…
Add table
Reference in a new issue