Skip to content

Commit

Permalink
Refactor create-astro (#6082)
Browse files Browse the repository at this point in the history
* refactor: new version of create-astro

* chore: update README

* fix(create-astro): update project name logic

* test(create-astro): fix test on windows

* test(create-astro): fix test on windows

* test(create-astro): remove unused import

* chore: remove log

* chore: increase test timeout

* fix: message when skipping

* fix: message for env.d.ts file

* fix: always hard exit

* fix: return from next-steps

* chore: add message

* refactor dependencies, bundle create-astro

* chore: disable create-astro typings

* chore: switch to arg

* chore: update message

* fix: split typescript into two steps, fix context test

* chore: update wording

* chore: update wording

* Update packages/create-astro/src/actions/dependencies.ts

Co-authored-by: Yan Thomas <[email protected]>

* refactor: move tests back to mocha/chai

* chore: update cli-kit

* update test script

* chore: add comment about setStdout

* chore: update cli-kit

* Update packages/create-astro/src/messages.ts

Co-authored-by: Sarah Rainsberger <[email protected]>

* Update packages/create-astro/src/messages.ts

Co-authored-by: Sarah Rainsberger <[email protected]>

* chore: update lockfile

* fix(create-astro): support scoped package names, improve project-name tests

* better git initialization

* update cli-kit

---------

Co-authored-by: Nate Moore <[email protected]>
Co-authored-by: Yan Thomas <[email protected]>
Co-authored-by: Sarah Rainsberger <[email protected]>
  • Loading branch information
4 people authored Feb 6, 2023
1 parent 91dc0f4 commit 8d2187d
Show file tree
Hide file tree
Showing 41 changed files with 1,234 additions and 1,328 deletions.
5 changes: 5 additions & 0 deletions .changeset/new-ravens-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-astro': major
---

Redesigned `create-astro` experience
35 changes: 11 additions & 24 deletions packages/create-astro/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ yarn create astro

```bash
# npm 6.x
npm create astro@latest my-astro-project --template starter
npm create astro@latest my-astro-project --template minimal

# npm 7+, extra double-dash is needed:
npm create astro@latest my-astro-project -- --template starter
npm create astro@latest my-astro-project -- --template minimal

# yarn
yarn create astro my-astro-project --template starter
yarn create astro my-astro-project --template minimal
```
[Check out the full list][examples] of example starter templates, available on GitHub.
[Check out the full list][examples] of example templates, available on GitHub.

You can also use any GitHub repo as a template:

Expand All @@ -40,26 +40,13 @@ May be provided in place of prompts

| Name | Description |
|:-------------|:----------------------------------------------------|
| `--template` | Specify the template name ([list][examples]) |
| `--commit` | Specify a specific Git commit or branch to use from this repo (by default, `main` branch of this repo will be used) |
| `--fancy` | For Windows users, `--fancy` will enable full unicode support |
| `--typescript` | Specify the [tsconfig][typescript] to use |
| `--yes`/`-y` | Skip prompts and use default values |

### Debugging

To debug `create-astro`, you can use the `--verbose` flag which will log the output of degit and some more information about the command, this can be useful when you encounter an error and want to report it.

```bash
# npm 6.x
npm create astro@latest my-astro-project --verbose

# npm 7+, extra double-dash is needed:
npm create astro@latest my-astro-project -- --verbose

# yarn
yarn create astro my-astro-project --verbose
```
| `--template <name> | Specify your template. |
| `--install / --no-install | Install dependencies (or not). |
| `--git / --no-git | Initialize git repo (or not). |
| `--yes (-y) | Skip all prompt by accepting defaults. |
| `--no (-n) | Skip all prompt by declining defaults. |
| `--dry-run | Walk through steps without executing. |
| `--skip-houston | Skip Houston animation. |

[examples]: https://github.com/withastro/astro/tree/main/examples
[typescript]: https://github.com/withastro/astro/tree/main/packages/astro/tsconfigs
1 change: 1 addition & 0 deletions packages/create-astro/grubby-group
Submodule grubby-group added at 9a401d
36 changes: 14 additions & 22 deletions packages/create-astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,36 @@
"exports": {
".": "./create-astro.mjs"
},
"main": "./create-astro.mjs",
"bin": {
"create-astro": "./create-astro.mjs"
},
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"build": "astro-scripts build \"src/index.ts\" --bundle && tsc",
"build:ci": "astro-scripts build \"src/index.ts\" --bundle",
"dev": "astro-scripts dev \"src/**/*.ts\"",
"test": "mocha --exit --timeout 20000"
"test": "mocha --exit --timeout 20000 --parallel"
},
"files": [
"dist",
"create-astro.js",
"tsconfigs"
"create-astro.js"
],
"//a": "MOST PACKAGES SHOULD GO IN DEV_DEPENDENCIES! THEY WILL BE BUNDLED.",
"//b": "DEPENDENCIES IS FOR UNBUNDLED PACKAGES",
"dependencies": {
"@astrojs/cli-kit": "^0.1.6",
"chalk": "^5.0.1",
"comment-json": "^4.2.3",
"@astrojs/cli-kit": "^0.2.2",
"chai": "^4.3.6",
"execa": "^6.1.0",
"giget": "^1.0.0",
"kleur": "^4.1.4",
"ora": "^6.1.0",
"prompts": "^2.4.2",
"strip-ansi": "^7.0.1",
"which-pm-runs": "^1.1.0",
"yargs-parser": "^21.0.1"
"mocha": "^9.2.2"
},
"devDependencies": {
"@types/chai": "^4.3.1",
"@types/degit": "^2.8.3",
"@types/mocha": "^9.1.1",
"@types/prompts": "^2.0.14",
"@types/which-pm-runs": "^1.0.0",
"@types/yargs-parser": "^21.0.0",
"arg": "^5.0.2",
"astro-scripts": "workspace:*",
"chai": "^4.3.6",
"mocha": "^9.2.2",
"uvu": "^0.5.3"
"strip-ansi": "^7.0.1",
"strip-json-comments": "^5.0.0",
"which-pm-runs": "^1.1.0"
},
"engines": {
"node": ">=16.12.0"
Expand Down
101 changes: 101 additions & 0 deletions packages/create-astro/src/actions/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import os from 'node:os';
import arg from 'arg';
import detectPackageManager from 'which-pm-runs';
import { prompt } from '@astrojs/cli-kit';

import { getName, getVersion } from '../messages.js';

export interface Context {
help: boolean;
prompt: typeof prompt;
cwd: string;
pkgManager: string;
username: string;
version: string;
skipHouston: boolean;
dryRun?: boolean;
yes?: boolean;
projectName?: string;
template?: string;
ref: string;
install?: boolean;
git?: boolean;
typescript?: string;
stdin?: typeof process.stdin;
stdout?: typeof process.stdout;
exit(code: number): never;
}


export async function getContext(argv: string[]): Promise<Context> {
const flags = arg({
'--template': String,
'--ref': String,
'--yes': Boolean,
'--no': Boolean,
'--install': Boolean,
'--no-install': Boolean,
'--git': Boolean,
'--no-git': Boolean,
'--typescript': String,
'--skip-houston': Boolean,
'--dry-run': Boolean,
'--help': Boolean,
'--fancy': Boolean,

'-y': '--yes',
'-n': '--no',
'-h': '--help',
}, { argv, permissive: true });

const pkgManager = detectPackageManager()?.name ?? 'npm';
const [username, version] = await Promise.all([getName(), getVersion()]);
let cwd = flags['_'][0] as string;
let {
'--help': help = false,
'--template': template,
'--no': no,
'--yes': yes,
'--install': install,
'--no-install': noInstall,
'--git': git,
'--no-git': noGit,
'--typescript': typescript,
'--fancy': fancy,
'--skip-houston': skipHouston,
'--dry-run': dryRun,
'--ref': ref,
} = flags;
let projectName = cwd;

if (no) {
yes = false;
if (install == undefined) install = false;
if (git == undefined) git = false;
if (typescript == undefined) typescript = 'strict';
}

skipHouston = ((os.platform() === 'win32' && !fancy) || skipHouston) ?? [yes, no, install, git, typescript].some((v) => v !== undefined);

const context: Context = {
help,
prompt,
pkgManager,
username,
version,
skipHouston,
dryRun,
projectName,
template,
ref: ref ?? 'latest',
yes,
install: install ?? (noInstall ? false : undefined),
git: git ?? (noGit ? false : undefined),
typescript,
cwd,
exit(code) {
process.exit(code);
}
}
return context;
}
43 changes: 43 additions & 0 deletions packages/create-astro/src/actions/dependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Context } from "./context";

import { title, info, spinner } from '../messages.js';
import { execa } from 'execa';

export async function dependencies(ctx: Pick<Context, 'install'|'yes'|'prompt'|'pkgManager'|'cwd'|'dryRun'>) {
let deps = ctx.install ?? ctx.yes;
if (deps === undefined) {
({ deps } = await ctx.prompt({
name: 'deps',
type: 'confirm',
label: title('deps'),
message: `Install dependencies?`,
hint: 'recommended',
initial: true,
}));
ctx.install = deps;
}

if (ctx.dryRun) {
await info('--dry-run', `Skipping dependency installation`);
} else if (deps) {
await spinner({
start: `Dependencies installing with ${ctx.pkgManager}...`,
end: 'Dependencies installed',
while: () => install({ pkgManager: ctx.pkgManager, cwd: ctx.cwd }),
});
} else {
await info(
ctx.yes === false ? 'deps [skip]' : 'No problem!',
'Remember to install dependencies after setup.'
);
}
}

async function install({ pkgManager, cwd }: { pkgManager: string, cwd: string }) {
const installExec = execa(pkgManager, ['install'], { cwd });
return new Promise<void>((resolve, reject) => {
installExec.on('error', (error) => reject(error));
installExec.on('close', () => resolve());
});
}

48 changes: 48 additions & 0 deletions packages/create-astro/src/actions/git.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Context } from "./context";
import fs from 'node:fs';
import path from 'node:path';

import { color } from '@astrojs/cli-kit';
import { title, info, spinner } from '../messages.js';
import { execa } from 'execa';

export async function git(ctx: Pick<Context, 'cwd'|'git'|'yes'|'prompt'|'dryRun'>) {
if (fs.existsSync(path.join(ctx.cwd, '.git'))) {
await info('Nice!', `Git has already been initialized`);
return
}
let _git = ctx.git ?? ctx.yes;
if (_git === undefined) {
({ git: _git } = await ctx.prompt({
name: 'git',
type: 'confirm',
label: title('git'),
message: `Initialize a new git repository?`,
hint: 'optional',
initial: true,
}));
}

if (ctx.dryRun) {
await info('--dry-run', `Skipping Git initialization`);
} else if (_git) {
await spinner({
start: 'Git initializing...',
end: 'Git initialized',
while: () => init({ cwd: ctx.cwd }),
});
} else {
await info(
ctx.yes === false ? 'git [skip]' : 'Sounds good!',
`You can always run ${color.reset('git init')}${color.dim(' manually.')}`
);
}
}

async function init({ cwd }: { cwd: string }) {
try {
await execa('git', ['init'], { cwd, stdio: 'ignore' });
await execa('git', ['add', '-A'], { cwd, stdio: 'ignore' });
await execa('git', ['commit', '-m', 'Initial commit from Astro', '--author="houston[bot] <[email protected]>"'], { cwd, stdio: 'ignore' });
} catch (e) {}
}
20 changes: 20 additions & 0 deletions packages/create-astro/src/actions/help.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { printHelp } from '../messages.js';

export function help() {
printHelp({
commandName: 'create-astro',
usage: '[dir] [...flags]',
headline: 'Scaffold Astro projects.',
tables: {
Flags: [
['--template <name>', 'Specify your template.'],
['--install / --no-install', 'Install dependencies (or not).'],
['--git / --no-git', 'Initialize git repo (or not).'],
['--yes (-y)', 'Skip all prompt by accepting defaults.'],
['--no (-n)', 'Skip all prompt by declining defaults.'],
['--dry-run', 'Walk through steps without executing.'],
['--skip-houston', 'Skip Houston animation.'],
],
},
});
}
23 changes: 23 additions & 0 deletions packages/create-astro/src/actions/intro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type Context } from './context';

import { banner, welcome, say } from '../messages.js';
import { label, color } from '@astrojs/cli-kit';
import { random } from '@astrojs/cli-kit/utils';

export async function intro(ctx: Pick<Context, 'skipHouston'|'version'|'username'>) {
if (!ctx.skipHouston) {
await say([
[
'Welcome',
'to',
label('astro', color.bgGreen, color.black),
color.green(`v${ctx.version}`) + ',',
`${ctx.username}!`,
],
random(welcome),
]);
await banner(ctx.version);
} else {
await banner(ctx.version);
}
}
15 changes: 15 additions & 0 deletions packages/create-astro/src/actions/next-steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Context } from "./context";
import path from 'node:path';

import { nextSteps, say } from '../messages.js';

export async function next(ctx: Pick<Context, 'cwd'|'pkgManager'|'skipHouston'>) {
let projectDir = path.relative(process.cwd(), ctx.cwd);
const devCmd = ctx.pkgManager === 'npm' ? 'npm run dev' : `${ctx.pkgManager} dev`;
await nextSteps({ projectDir, devCmd });

if (!ctx.skipHouston) {
await say(['Good luck out there, astronaut! 🚀']);
}
return;
}
Loading

0 comments on commit 8d2187d

Please sign in to comment.