Skip to content

Commit

Permalink
Merge branch 'static-ci' of https://github.com/Mist3rBru/clack into s…
Browse files Browse the repository at this point in the history
…tatic-ci
  • Loading branch information
orochaa committed Nov 26, 2024
2 parents 45ee73b + 7e34e93 commit e064e4c
Show file tree
Hide file tree
Showing 7 changed files with 2,226 additions and 1,777 deletions.
5 changes: 5 additions & 0 deletions .changeset/thin-moose-tease.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clack/prompts': patch
---

Adapt `spinner` to CI environment
3 changes: 2 additions & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
},
"scripts": {
"start": "jiti ./index.ts",
"spinner": "jiti ./spinner.ts"
"spinner": "jiti ./spinner.ts",
"spinner-ci": "npx cross-env GITHUB_ACTIONS=\"true\" jiti ./spinner-ci.ts"
},
"devDependencies": {
"jiti": "^1.17.0"
Expand Down
36 changes: 36 additions & 0 deletions examples/basic/spinner-ci.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* This example addresses a issue reported in GitHub Actions where `spinner` was excessively writing messages,
* leading to confusion and cluttered output.
* To enhance the CI workflow and provide a smoother experience,
* the following changes have been made only for CI environment:
* - Messages will now only be written when a `spinner` method is called and the message updated, preventing unnecessary message repetition.
* - There will be no loading dots animation, instead it will be always `...`
* - Instead of erase the previous message, action that is blocked during CI, it will just write a new one.
*
* Issue: https://github.com/natemoo-re/clack/issues/168
*/
import * as p from '@clack/prompts';

const s = p.spinner();
let progress = 0;
let counter = 0;
let loop: NodeJS.Timer;

p.intro('Running spinner in CI environment');
s.start('spinner.start');
new Promise((resolve) => {
loop = setInterval(() => {
if (progress % 1000 === 0) {
counter++;
}
progress += 100;
s.message(`spinner.message [${counter}]`);
if (counter > 6) {
clearInterval(loop);
resolve(true);
}
}, 100);
}).then(() => {
s.stop('spinner.stop');
p.outro('Done');
});
2 changes: 1 addition & 1 deletion examples/basic/spinner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as p from '@clack/prompts';
p.intro('spinner start...');

const spin = p.spinner();
const total = 10000;
const total = 6000;
let progress = 0;
spin.start();

Expand Down
3 changes: 2 additions & 1 deletion packages/prompts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
"dependencies": {
"@clack/core": "workspace:*",
"picocolors": "^1.0.0",
"sisteransi": "^1.0.5"
"sisteransi": "^1.0.5",
"std-env": "^3.4.3"
},
"devDependencies": {
"is-unicode-supported": "^1.3.0"
Expand Down
32 changes: 24 additions & 8 deletions packages/prompts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import isUnicodeSupported from 'is-unicode-supported';
import color from 'picocolors';
import { cursor, erase } from 'sisteransi';
import { isCI } from 'std-env';

export { isCancel } from '@clack/core';

Expand Down Expand Up @@ -644,6 +645,7 @@ export const spinner = () => {
let loop: NodeJS.Timeout;
let isSpinnerActive: boolean = false;
let _message: string = '';
let _prevMessage: string | undefined = undefined;

const handleExit = (code: number) => {
const msg = code > 1 ? 'Something went wrong' : 'Canceled';
Expand Down Expand Up @@ -672,44 +674,58 @@ export const spinner = () => {
process.removeListener('exit', handleExit);
};

const clearPrevMessage = () => {
if (_prevMessage === undefined) return;
if (isCI) process.stdout.write('\n');
const prevLines = _prevMessage.split('\n');
process.stdout.write(cursor.move(-999, prevLines.length - 1));
process.stdout.write(erase.down(prevLines.length));
};

const parseMessage = (msg: string): string => {
return msg.replace(/\.+$/, '');
};

const start = (msg: string = ''): void => {
isSpinnerActive = true;
unblock = block();
_message = msg.replace(/\.+$/, '');
_message = parseMessage(msg);
process.stdout.write(`${color.gray(S_BAR)}\n`);
let frameIndex = 0;
let dotsTimer = 0;
registerHooks();
loop = setInterval(() => {
if (isCI && _message === _prevMessage) {
return;
}
clearPrevMessage();
_prevMessage = _message;
const frame = color.magenta(frames[frameIndex]);
const loadingDots = '.'.repeat(Math.floor(dotsTimer)).slice(0, 3);
process.stdout.write(cursor.move(-999, 0));
process.stdout.write(erase.down(1));
const loadingDots = isCI ? '...' : '.'.repeat(Math.floor(dotsTimer)).slice(0, 3);
process.stdout.write(`${frame} ${_message}${loadingDots}`);
frameIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0;
dotsTimer = dotsTimer < frames.length ? dotsTimer + 0.125 : 0;
}, delay);
};

const stop = (msg: string = '', code: number = 0): void => {
_message = msg ?? _message;
isSpinnerActive = false;
clearInterval(loop);
clearPrevMessage();
const step =
code === 0
? color.green(S_STEP_SUBMIT)
: code === 1
? color.red(S_STEP_CANCEL)
: color.red(S_STEP_ERROR);
process.stdout.write(cursor.move(-999, 0));
process.stdout.write(erase.down(1));
_message = parseMessage(msg ?? _message);
process.stdout.write(`${step} ${_message}\n`);
clearHooks();
unblock();
};

const message = (msg: string = ''): void => {
_message = msg ?? _message;
_message = parseMessage(msg ?? _message);
};

return {
Expand Down
Loading

0 comments on commit e064e4c

Please sign in to comment.