Skip to content

feat: added sub-spinner labels for some spinner task groups #710

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

Merged
merged 12 commits into from
Aug 26, 2023
20 changes: 15 additions & 5 deletions src/create/createWithOptions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as prompts from "@clack/prompts";
import { $ } from "execa";

import { withSpinner } from "../shared/cli/spinners.js";
import { withSpinner, withSpinners } from "../shared/cli/spinners.js";
import { doesRepositoryExist } from "../shared/doesRepositoryExist.js";
import { OctokitAndOptions } from "../shared/options/readOptions.js";
import { addToolAllContributors } from "../steps/addToolAllContributors.js";
Expand All @@ -15,10 +15,20 @@ export async function createWithOptions({
octokit,
options,
}: OctokitAndOptions) {
await withSpinner("Creating repository structure", async () => {
await writeStructure(options);
await writeReadme(options);
});
await withSpinners("Creating repository structure", [
[
"Writing structure",
async () => {
await writeStructure(options);
},
],
[
"Writing README.md",
async () => {
await writeReadme(options);
},
],
]);

if (!options.excludeContributors) {
await withSpinner("Adding contributors to table", async () => {
Expand Down
26 changes: 18 additions & 8 deletions src/initialize/initializeWithOptions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { withSpinner } from "../shared/cli/spinners.js";
import { withSpinner, withSpinners } from "../shared/cli/spinners.js";
import { OctokitAndOptions } from "../shared/options/readOptions.js";
import { addOwnerAsAllContributor } from "../steps/addOwnerAsAllContributor.js";
import { clearChangelog } from "../steps/clearChangelog.js";
Expand All @@ -15,13 +15,23 @@ export async function initializeWithOptions({
octokit,
options,
}: OctokitAndOptions) {
await withSpinner("Initializing local files", async () => {
await updateLocalFiles(options);
await updateReadme();
await clearChangelog();
await updateAllContributorsTable(options);
await resetGitTags();
});
await withSpinners("Initializing local files", [
[
"Updating local files",
async () => {
await updateLocalFiles(options);
},
],
["Updating README.md", updateReadme],
["Clearing changelog", clearChangelog],
[
"Updating all-contributors table",
async () => {
await updateAllContributorsTable(options);
},
],
["Resetting Git tags", resetGitTags],
]);

if (!options.excludeContributors) {
await withSpinner("Updating existing contributor details", async () => {
Expand Down
36 changes: 28 additions & 8 deletions src/migrate/migrateWithOptions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { withSpinner } from "../shared/cli/spinners.js";
import { withSpinner, withSpinners } from "../shared/cli/spinners.js";
import { OctokitAndOptions } from "../shared/options/readOptions.js";
import { clearUnnecessaryFiles } from "../steps/clearUnnecessaryFiles.js";
import { detectExistingContributors } from "../steps/detectExistingContributors.js";
Expand All @@ -14,13 +14,33 @@ export async function migrateWithOptions({
octokit,
options,
}: OctokitAndOptions) {
await withSpinner("Migrating repository structure", async () => {
await clearUnnecessaryFiles();
await writeStructure(options);
await writeReadme(options);
await updateLocalFiles(options);
await updateAllContributorsTable(options);
});
await withSpinners("Migrating repository structure", [
["Clearing unnecessary files", clearUnnecessaryFiles],
[
"Writing structure",
async () => {
await writeStructure(options);
},
],
[
"Writing README.md",
async () => {
await writeReadme(options);
},
],
[
"Updating local files",
async () => {
await updateLocalFiles(options);
},
],
[
"Updating all-contributors table",
async () => {
await updateAllContributorsTable(options);
},
],
]);

if (octokit) {
await withSpinner("Initializing GitHub repository", async () => {
Expand Down
11 changes: 10 additions & 1 deletion src/shared/cli/lines.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import chalk from "chalk";

export function logLine(line?: string) {
console.log([chalk.gray("│"), line].filter(Boolean).join(" "));
console.log(makeLine(line));
}

export function logNewSection(line: string) {
logLine();
console.log(`◇ ${line}`);
}

export function makeLine(line: string | undefined) {
return [chalk.gray("│"), line].filter(Boolean).join(" ");
}
56 changes: 49 additions & 7 deletions src/shared/cli/spinners.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import * as prompts from "@clack/prompts";
import chalk from "chalk";
import readline from "readline";

import { logLine, logNewSection, makeLine } from "./lines.js";
import { lowerFirst } from "./lowerFirst.js";
import { startLineWithDots } from "./startLineWithDots.js";

const s = prompts.spinner();

export type SpinnerTask<Return> = () => Promise<Return>;

export type LabeledSpinnerTask<Return> = [string, SpinnerTask<Return>];

export async function withSpinner<Return>(
label: string,
callback: () => Promise<Return>,
task: SpinnerTask<Return>,
) {
s.start(`${label}...`);

try {
const result = await callback();
const result = await task();

if (result === false) {
s.stop(chalk.yellow(`⚠️ Error ${lowerFirst(label)}.`));
} else {
s.stop(chalk.green(`✅ Passed ${lowerFirst(label)}.`));
}
s.stop(chalk.green(`✅ Passed ${lowerFirst(label)}.`));

return result;
} catch (error) {
Expand All @@ -27,3 +30,42 @@ export async function withSpinner<Return>(
throw new Error(`Failed ${lowerFirst(label)}`, { cause: error });
}
}

export async function withSpinners(
label: string,
tasks: LabeledSpinnerTask<void>[],
) {
logNewSection(`${label}...`);

let currentLabel!: string;
let lastLogged!: string;

try {
for (const [label, run] of tasks) {
currentLabel = label;

const line = makeLine(chalk.gray(` - ${label}`));
const stopWriting = startLineWithDots(line);

await run();

const lineLength = stopWriting();
lastLogged = chalk.gray(`${line} ✔️\n`);

readline.clearLine(process.stdout, -1);
readline.moveCursor(process.stdout, -lineLength, 0);
process.stdout.write(lastLogged);
}

readline.moveCursor(process.stdout, -lastLogged.length, -tasks.length - 2);
readline.clearScreenDown(process.stdout);

logNewSection(chalk.green(`✅ Passed ${lowerFirst(label)}.`));
} catch (error) {
const descriptor = `${lowerFirst(label)} > ${lowerFirst(currentLabel)}`;

logLine(chalk.red(`❌ Error ${descriptor}.`));

throw new Error(`Failed ${descriptor}`, { cause: error });
}
}
37 changes: 37 additions & 0 deletions src/shared/cli/startLineWithDots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import readline from "readline";

export function startLineWithDots(line: string) {
let dots = 0;
let lastLogged!: string;

function clearLine() {
readline.clearLine(process.stdout, -1);
readline.moveCursor(process.stdout, -lastLogged.length, 0);
}

function writeLine() {
dots = (dots + 1) % 4;

const toLog = `${line}${".".repeat(dots)}`;

process.stdout.write(toLog);

lastLogged = toLog;

return toLog;
}

writeLine();

const timer = setInterval(() => {
clearLine();
writeLine();
dots += 1;
}, 500);

return () => {
clearLine();
clearInterval(timer);
return lastLogged.length;
};
}