Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a verbose flag to create-astro #2429

Merged
merged 7 commits into from
Jan 21, 2022
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: 5 additions & 0 deletions .changeset/gentle-cats-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-astro': patch
---

Added an option to create-astro to use verbose logging which should help debug degit issues
15 changes: 15 additions & 0 deletions packages/create-astro/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,19 @@ May be provided in place of prompts
| `--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) |

### 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 init astro my-astro-project --verbose

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

# yarn
yarn create astro my-astro-project --verbose
```

[examples]: https://github.com/withastro/astro/tree/main/examples
23 changes: 19 additions & 4 deletions packages/create-astro/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import yargs from 'yargs-parser';
import { FRAMEWORKS, COUNTER_COMPONENTS } from './frameworks.js';
import { TEMPLATES } from './templates.js';
import { createConfig } from './config.js';
import { logger, defaultLogLevel } from './logger.js';

// NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed
// to no longer require `--` to pass args and instead pass `--` directly to us. This
Expand All @@ -31,6 +32,7 @@ const { version } = JSON.parse(fs.readFileSync(new URL('../package.json', import
const POSTPROCESS_FILES = ['package.json', 'astro.config.mjs', 'CHANGELOG.md']; // some files need processing after copying.

export async function main() {
logger.debug('Verbose logging turned on');
console.log(`\n${bold('Welcome to Astro!')} ${gray(`(create-astro v${version})`)}`);
console.log(`If you encounter a problem, visit ${cyan('https://github.com/withastro/astro/issues')} to search or file a new issue.\n`);

Expand Down Expand Up @@ -75,7 +77,13 @@ export async function main() {
const emitter = degit(`${templateTarget}${hash}`, {
cache: false,
force: true,
verbose: false,
verbose: defaultLogLevel === 'debug' ? true : false,
});

logger.debug('Initialized degit with following config:', `${templateTarget}${hash}`, {
cache: false,
force: true,
verbose: defaultLogLevel === 'debug' ? true : false,
});

const selectedTemplate = TEMPLATES.find((template) => template.value === options.template);
Expand All @@ -99,11 +107,14 @@ export async function main() {

// Copy
try {
// emitter.on('info', info => { console.log(info.message) });
emitter.on('info', (info) => {
logger.debug(info.message);
});
console.log(`${green(`>`)} ${gray(`Copying project files...`)}`);
await emitter.clone(cwd);
} catch (err: any) {
// degit is compiled, so the stacktrace is pretty noisy. Just report the message.
// degit is compiled, so the stacktrace is pretty noisy. Only report the stacktrace when using verbose mode.
logger.debug(err);
console.error(red(err.message));

// Warning for issue #655
Expand All @@ -115,7 +126,11 @@ export async function main() {
// Helpful message when encountering the "could not find commit hash for ..." error
if (err.code === 'MISSING_REF') {
console.log(yellow("This seems to be an issue with degit. Please check if you have 'git' installed on your system, and install it if you don't have (https://git-scm.com)."));
console.log(yellow("If you do have 'git' installed, please file a new issue here: https://github.com/withastro/astro/issues"));
console.log(
yellow(
"If you do have 'git' installed, please run this command with the --verbose flag and file a new issue with the command output here: https://github.com/withastro/astro/issues"
Mikkel-T marked this conversation as resolved.
Show resolved Hide resolved
)
);
}
process.exit(1);
}
Expand Down
143 changes: 143 additions & 0 deletions packages/create-astro/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { bold, blue, dim, red, yellow } from 'kleur/colors';
import { Writable } from 'stream';
import { format as utilFormat } from 'util';

type ConsoleStream = Writable & {
fd: 1 | 2;
};

function getLoggerLocale(): string {
const defaultLocale = 'en-US';
if (process.env.LANG) {
const extractedLocale = process.env.LANG.split('.')[0].replace(/_/g, '-');
// Check if language code is atleast two characters long (ie. en, es).
// NOTE: if "c" locale is encountered, the default locale will be returned.
if (extractedLocale.length < 2) return defaultLocale;

This comment was marked as resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not really sure, this code is just a straight copy of the logger implemented in astro core but with some parts removed that didn't seem necessary for create-astro, but I don't think that it would return anything like that, I am not very familiar with env variables though so I don't actually know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome

else return extractedLocale;
} else return defaultLocale;
}

const dt = new Intl.DateTimeFormat(getLoggerLocale(), {
hour: '2-digit',
minute: '2-digit',
});

export const defaultLogDestination = new Writable({
objectMode: true,
write(event: LogMessage, _, callback) {
let dest: ConsoleStream = process.stderr;
if (levels[event.level] < levels['error']) dest = process.stdout;

dest.write(dim(dt.format(new Date()) + ' '));

let type = event.type;
if (type) {
switch (event.level) {
case 'info':
type = bold(blue(type));
break;
case 'warn':
type = bold(yellow(type));
break;
case 'error':
type = bold(red(type));
break;
}

dest.write(`[${type}] `);
}

dest.write(utilFormat(...event.args));
dest.write('\n');

callback();
},
});

interface LogWritable<T> extends Writable {
write: (chunk: T) => boolean;
}

export type LoggerLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'; // same as Pino
export type LoggerEvent = 'debug' | 'info' | 'warn' | 'error';

export let defaultLogLevel: LoggerLevel;
if (process.argv.includes('--verbose')) {
defaultLogLevel = 'debug';
} else if (process.argv.includes('--silent')) {
defaultLogLevel = 'silent';
} else {
defaultLogLevel = 'info';
}

export interface LogOptions {
dest?: LogWritable<LogMessage>;
level?: LoggerLevel;
}

export const defaultLogOptions: Required<LogOptions> = {
dest: defaultLogDestination,
level: defaultLogLevel,
};

export interface LogMessage {
type: string | null;
level: LoggerLevel;
message: string;
args: Array<any>;
}

export const levels: Record<LoggerLevel, number> = {
debug: 20,
info: 30,
warn: 40,
error: 50,
silent: 90,
};

/** Full logging API */
export function log(opts: LogOptions = {}, level: LoggerLevel, type: string | null, ...args: Array<any>) {
const logLevel = opts.level ?? defaultLogOptions.level;
const dest = opts.dest ?? defaultLogOptions.dest;
const event: LogMessage = {
type,
level,
args,
message: '',
};

// test if this level is enabled or not
if (levels[logLevel] > levels[level]) {
return; // do nothing
}

dest.write(event);
}

/** Emit a message only shown in debug mode */
export function debug(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'debug', type, ...messages);
}

/** Emit a general info message (be careful using this too much!) */
export function info(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'info', type, ...messages);
}

/** Emit a warning a user should be aware of */
export function warn(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'warn', type, ...messages);
}

/** Emit a fatal error message the user should address. */
export function error(opts: LogOptions, type: string | null, ...messages: Array<any>) {
return log(opts, 'error', type, ...messages);
}

// A default logger for when too lazy to pass LogOptions around.
export const logger = {
debug: debug.bind(null, defaultLogOptions, 'debug'),
info: info.bind(null, defaultLogOptions, 'info'),
warn: warn.bind(null, defaultLogOptions, 'warn'),
error: error.bind(null, defaultLogOptions, 'error'),
};