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

Allow skuba configure to accept stdin input #1558

Merged
merged 11 commits into from
Jun 20, 2024
5 changes: 5 additions & 0 deletions .changeset/stupid-oranges-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'skuba': minor
---

configure: Accept template data from stdin to allow for integration testing
41 changes: 35 additions & 6 deletions src/cli/configure/ensureTemplateCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'path';
import chalk from 'chalk';
import fs from 'fs-extra';
import type { NormalizedReadResult } from 'read-pkg-up';
import { z } from 'zod';

import { copyFiles, createEjsRenderer } from '../../utils/copy';
import { log } from '../../utils/logging';
Expand All @@ -11,7 +12,11 @@ import {
ensureTemplateConfigDeletion,
} from '../../utils/template';
import { hasStringProp } from '../../utils/validation';
import { getTemplateConfig, runForm } from '../init/getConfig';
import {
getTemplateConfig,
readJSONFromStdIn,
runForm,
} from '../init/getConfig';

import { formatPackage } from './processing/package';

Expand All @@ -21,6 +26,28 @@ interface Props {
manifest: NormalizedReadResult;
}

const templateDataSchema = z.object({ templateData: z.record(z.string()) });

const getTemplateDataFromStdIn = async (
templateConfig: TemplateConfig,
): Promise<Record<string, string>> => {
const config = await readJSONFromStdIn();
const data = templateDataSchema.parse(config);

templateConfig.fields.forEach((field) => {
const value = data.templateData[field.name];
if (value === undefined) {
throw new Error(`Missing field: ${field.name}`);
}

if (field.validate && !field.validate(value)) {
throw new Error(`Invalid value for field: ${field.name}`);
}
});

return data.templateData;
};

export const ensureTemplateCompletion = async ({
destinationRoot,
include,
Expand All @@ -37,11 +64,13 @@ export const ensureTemplateCompletion = async ({
: 'template';

log.newline();
const templateData = await runForm({
choices: templateConfig.fields,
message: chalk.bold(`Complete ${chalk.cyan(templateName)}:`),
name: 'customAnswers',
});
const templateData = process.stdin.isTTY
? await runForm({
choices: templateConfig.fields,
message: chalk.bold(`Complete ${chalk.cyan(templateName)}:`),
name: 'customAnswers',
})
: await getTemplateDataFromStdIn(templateConfig);

const updatedPackageJson = await formatPackage(manifest.packageJson);
const packageJsonFilepath = path.join(destinationRoot, 'package.json');
Expand Down
9 changes: 6 additions & 3 deletions src/cli/configure/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import { getEntryPoint } from './getEntryPoint';
import { getProjectType } from './getProjectType';

const shouldApply = async (name: string) => {
if (!process.stdin.isTTY) {
return 'yes';
}
const prompt = new Select({
choices: ['yes', 'no'] as const,
message: 'Apply changes?',
Expand Down Expand Up @@ -118,8 +121,8 @@ export const configure = async () => {
log.warn(log.bold('✗ Failed to install dependencies. Resume with:'));

log.newline();
log.plain(log.bold(packageManager, 'install'));
log.plain(log.bold(packageManager, 'run', 'format'));
log.plain(log.bold(packageManager.install));
log.plain(log.bold(packageManager, 'format'));

log.newline();
process.exitCode = 1;
Expand All @@ -132,7 +135,7 @@ export const configure = async () => {
log.ok(log.bold('✔ All done! Try running:'));

log.newline();
log.plain(log.bold(packageManager, 'run', 'format'));
log.plain(log.bold(packageManager, 'format'));
}

log.newline();
Expand Down
8 changes: 7 additions & 1 deletion src/cli/init/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export const configureFromPrompt = async (): Promise<InitConfig> => {
};
};

const configureFromPipe = async (): Promise<InitConfig> => {
export const readJSONFromStdIn = async () => {
let text = '';

await new Promise((resolve) =>
Expand All @@ -312,6 +312,12 @@ const configureFromPipe = async (): Promise<InitConfig> => {
process.exit(1);
}

return value;
};

const configureFromPipe = async (): Promise<InitConfig> => {
const value = await readJSONFromStdIn();

const result = initConfigInputSchema.safeParse(value);

if (!result.success) {
Expand Down
Loading