Skip to content

Commit

Permalink
Merge branch 'main' of github.com:chromaui/chromatic-cli into turbosn…
Browse files Browse the repository at this point in the history
…ap-log-upgrades
  • Loading branch information
ethriel3695 committed Sep 8, 2023
2 parents e4b621f + cc4c525 commit ab4a26e
Show file tree
Hide file tree
Showing 22 changed files with 130 additions and 24 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# 7.1.0 - 2023-09-07

- [812](https://github.com/chromaui/chromatic-cli/pull/812) Allow running a build from a repo with only one commit when not in CI
- [810](https://github.com/chromaui/chromatic-cli/pull/810) Add `onTaskStart`, and a new typed field `ctx.task`
- [808](https://github.com/chromaui/chromatic-cli/pull/808) Add `onTaskError` option to report errors to node consumers
- [813](https://github.com/chromaui/chromatic-cli/pull/813) Rename `onTaskError` to `experimental_onTaskError`

# 7.0.0 - 2023-09-04

- [789](https://github.com/chromaui/chromatic-cli/pull/789) Use `@antfu/ni` to support `pnpm` for Storybook build
- [805](https://github.com/chromaui/chromatic-cli/pull/805) Add a `onTaskProgress` option and report progress on it

This is a potentially breaking change due to the introduction of [@antfu/ni](https://github.com/antfu/ni) to handle running the `storybook build` command in the **Build Storybook** step.

# 6.24.1 - 2023-08-25

- [803](https://github.com/chromaui/chromatic-cli/pull/803) Support Mode Name as Suffix for Build Progress Indicator
Expand Down
10 changes: 9 additions & 1 deletion node-src/git/getCommitAndBranch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,19 @@ describe('getCommitAndBranch', () => {
expect(info).toMatchObject({ branch: 'master' });
});

it('throws when there is only one commit', async () => {
it('throws when there is only one commit, CI', async () => {
envCi.mockReturnValue({ isCi: true });
hasPreviousCommit.mockResolvedValue(false);
await expect(getCommitAndBranch({ log })).rejects.toThrow('Found only one commit');
});

it('does NOT throw when there is only one commit, non-CI', async () => {
envCi.mockReturnValue({ isCi: false });
hasPreviousCommit.mockResolvedValue(false);
const info = await getCommitAndBranch({ log });
expect(info).toMatchObject({});
});

describe('with branchName', () => {
it('uses provided branchName as branch', async () => {
const info = await getCommitAndBranch({ log }, { branchName: 'foobar' });
Expand Down
9 changes: 7 additions & 2 deletions node-src/git/getCommitAndBranch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,20 @@ export default async function getCommitAndBranch(
CHROMATIC_PULL_REQUEST_SHA,
CHROMATIC_SLUG,
} = process.env;
const { isCi, service, prBranch, branch: ciBranch, commit: ciCommit, slug: ciSlug } = envCi();

const isFromEnvVariable = CHROMATIC_SHA && CHROMATIC_BRANCH; // Our GitHub Action also sets these
const isTravisPrBuild = TRAVIS_EVENT_TYPE === 'pull_request';
const isGitHubAction = GITHUB_ACTIONS === 'true';
const isGitHubPrBuild = GITHUB_EVENT_NAME === 'pull_request';

if (!(await hasPreviousCommit())) {
throw new Error(gitOneCommit(isGitHubAction));
const message = gitOneCommit(isGitHubAction);
if (isCi) {
throw new Error(message);
} else {
log.warn(message);
}
}

if (isFromEnvVariable) {
Expand Down Expand Up @@ -117,7 +123,6 @@ export default async function getCommitAndBranch(
slug = GITHUB_REPOSITORY;
}

const { isCi, service, prBranch, branch: ciBranch, commit: ciCommit, slug: ciSlug } = envCi();
const ciService = process.env.CHROMATIC_ACTION ? 'chromaui/action' : service;
slug = slug || ciSlug;

Expand Down
2 changes: 2 additions & 0 deletions node-src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ interface Output {
inheritedCaptureCount: number;
}

export type { Flags, Options, TaskName, Context } from './types';

export async function run({
argv = [],
flags,
Expand Down
20 changes: 17 additions & 3 deletions node-src/lib/tasks.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import chalk from 'chalk';
import Listr from 'listr';
import pluralize from 'pluralize';
import { Context, Task } from '../types';
import { Context, Task, TaskName } from '../types';

type ValueFn = string | ((ctx: Context, task: Task) => string);

export const createTask = ({ title, steps, ...config }): Listr.ListrTask<Context> => ({
type TaskInput = Omit<Listr.ListrTask<Context>, 'task'> & {
name: TaskName;
steps: ((ctx: Context, task: Listr.ListrTaskWrapper<Context> | Task) => void | Promise<void>)[];
};

export const createTask = ({
name,
title,
steps,
...config
}: TaskInput): Listr.ListrTask<Context> => ({
title,
task: async (ctx: Context, task: Listr.ListrTaskWrapper<Context>) => {
ctx.task = name;
ctx.title = title;
ctx.startedAt = Number.isInteger(ctx.now) ? ctx.now : new Date().getTime();

ctx.options.experimental_onTaskStart?.({ ...ctx });

// eslint-disable-next-line no-restricted-syntax
for (const step of steps) {
// eslint-disable-next-line no-await-in-loop
await step(ctx, task);
}

ctx.options.onTaskComplete?.({ ...ctx });
ctx.options.experimental_onTaskComplete?.({ ...ctx });
},
...config,
});
Expand Down
21 changes: 21 additions & 0 deletions node-src/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ const getContext = (
},
packagePath: '',
statsPath: 'preview-stats.json',
options: {},
...parseArgs(argv),
} as any;
};
Expand All @@ -351,6 +352,26 @@ it('fails on missing project token', async () => {
expect(ctx.testLogger.errors[0]).toMatch(/Missing project token/);
});

// Note this tests options errors, but not fatal task or runtime errors.
it('passes options error to experimental_onTaskError', async () => {
const ctx = getContext([]);
ctx.options = {
experimental_onTaskError: jest.fn(),
} as any;

ctx.options.experimental_onTaskError = jest.fn();
ctx.env.CHROMATIC_PROJECT_TOKEN = '';
await runBuild(ctx);

await expect(ctx.options.experimental_onTaskError).toHaveBeenCalledWith(
expect.anything(), // Context
expect.objectContaining({
formattedError: expect.stringContaining('Missing project token'), // Long formatted error fatalError https://github.com/chromaui/chromatic-cli/blob/217e77671179748eb4ddb8becde78444db93d067/node-src/ui/messages/errors/fatalError.ts#L11
originalError: expect.any(Error),
})
);
});

it('runs in simple situations', async () => {
const ctx = getContext(['--project-token=asdf1234']);
await runBuild(ctx);
Expand Down
8 changes: 8 additions & 0 deletions node-src/runBuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export async function runBuild(ctx: Context, extraOptions?: Partial<Options>) {
} catch (e) {
ctx.log.info('');
ctx.log.error(fatalError(ctx, [e]));
ctx.options.experimental_onTaskError?.(ctx, {
formattedError: fatalError(ctx, [e]),
originalError: e,
});
setExitCode(ctx, exitCodes.INVALID_OPTIONS, true);
return;
}
Expand Down Expand Up @@ -71,6 +75,10 @@ export async function runBuild(ctx: Context, extraOptions?: Partial<Options>) {
}
} catch (error) {
const errors = [].concat(error); // GraphQLClient might throw an array of errors
ctx.options.experimental_onTaskError?.(ctx, {
formattedError: fatalError(ctx, errors),
originalError: error,
});

if (errors.length && !ctx.userError) {
ctx.log.info('');
Expand Down
1 change: 1 addition & 0 deletions node-src/tasks/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const setAuthorizationToken = async (ctx: Context) => {
};

export default createTask({
name: 'auth',
title: initial.title,
steps: [transitionTo(authenticating), setAuthorizationToken, transitionTo(authenticated, true)],
});
1 change: 1 addition & 0 deletions node-src/tasks/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const buildStorybook = async (ctx: Context) => {
};

export default createTask({
name: 'build',
title: initial.title,
skip: async (ctx) => {
if (ctx.skip) return true;
Expand Down
1 change: 1 addition & 0 deletions node-src/tasks/gitInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ export const setGitInfo = async (ctx: Context, task: Task) => {
};

export default createTask({
name: 'gitInfo',
title: initial.title,
steps: [transitionTo(pending), setGitInfo],
});
1 change: 1 addition & 0 deletions node-src/tasks/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export const announceBuild = async (ctx: Context) => {
};

export default createTask({
name: 'initialize',
title: initial.title,
skip: (ctx: Context) => ctx.skip,
steps: [transitionTo(pending), setEnvironment, announceBuild, transitionTo(success, true)],
Expand Down
1 change: 1 addition & 0 deletions node-src/tasks/prepareWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const runPrepareWorkspace = async (ctx: Context, task: Task) => {
};

export default createTask({
name: 'prepareWorkspace',
title: initial.title,
steps: [transitionTo(pending), runPrepareWorkspace, transitionTo(success, true)],
});
1 change: 1 addition & 0 deletions node-src/tasks/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export const generateReport = async (ctx: Context) => {
};

export default createTask({
name: 'report',
title: initial.title,
skip: (ctx: Context) => ctx.skip,
steps: [transitionTo(pending), generateReport, transitionTo(success, true)],
Expand Down
1 change: 1 addition & 0 deletions node-src/tasks/restoreWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const runRestoreWorkspace = async () => {
};

export default createTask({
name: 'restoreWorkspace',
title: initial.title,
steps: [transitionTo(pending), runRestoreWorkspace, transitionTo(success, true)],
});
10 changes: 5 additions & 5 deletions node-src/tasks/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe('takeSnapshots', () => {
expect(ctx.exitCode).toBe(3);
});

it('calls onTaskProgress with progress', async () => {
it('calls experimental_onTaskProgress with progress', async () => {
const client = { runQuery: jest.fn(), setAuthorization: jest.fn() };
const build = {
app: { repository: { provider: 'github' } },
Expand All @@ -122,7 +122,7 @@ describe('takeSnapshots', () => {
env,
git: { matchesBranch },
log,
options: { onTaskProgress: jest.fn() },
options: { experimental_onTaskProgress: jest.fn() },
build,
} as any;

Expand All @@ -138,13 +138,13 @@ describe('takeSnapshots', () => {

await takeSnapshots(ctx, {} as any);

expect(ctx.options.onTaskProgress).toHaveBeenCalledTimes(2);
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledTimes(2);
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 1,
total: 5,
unit: 'snapshots',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 3,
total: 5,
unit: 'snapshots',
Expand Down
3 changes: 2 additions & 1 deletion node-src/tasks/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const takeSnapshots = async (ctx: Context, task: Task) => {
const updateProgress = throttle(
({ cursor, label }) => {
task.output = pending(ctx, { cursor, label }).output;
ctx.options.onTaskProgress?.(
ctx.options.experimental_onTaskProgress?.(
{ ...ctx },
{ progress: cursor, total: actualTestCount, unit: 'snapshots' }
);
Expand Down Expand Up @@ -145,6 +145,7 @@ export const takeSnapshots = async (ctx: Context, task: Task) => {
};

export default createTask({
name: 'snapshot',
title: initial.title,
skip: (ctx: Context) => {
if (ctx.skip) return true;
Expand Down
1 change: 1 addition & 0 deletions node-src/tasks/storybookInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const setStorybookInfo = async (ctx: Context) => {
};

export default createTask({
name: 'storybookInfo',
title: initial.title,
skip: (ctx: Context) => ctx.skip,
steps: [transitionTo(pending), setStorybookInfo, transitionTo(success, true)],
Expand Down
14 changes: 7 additions & 7 deletions node-src/tasks/upload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ describe('uploadStorybook', () => {
expect(ctx.isolatorUrl).toBe('https://asdqwe.chromatic.com/iframe.html');
});

it('calls onTaskProgress with progress', async () => {
it('calls experimental_onTaskProgress with progress', async () => {
const client = { runQuery: jest.fn() };
client.runQuery.mockReturnValue({
getUploadUrls: {
Expand Down Expand Up @@ -294,29 +294,29 @@ describe('uploadStorybook', () => {
log,
http,
sourceDir: '/static/',
options: { onTaskProgress: jest.fn() },
options: { experimental_onTaskProgress: jest.fn() },
fileInfo,
announcedBuild: { id: '1' },
} as any;
await uploadStorybook(ctx, {} as any);

expect(ctx.options.onTaskProgress).toHaveBeenCalledTimes(4);
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledTimes(4);
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 21,
total: 84,
unit: 'bytes',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 42,
total: 84,
unit: 'bytes',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 63,
total: 84,
unit: 'bytes',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
expect(ctx.options.experimental_onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 84,
total: 84,
unit: 'bytes',
Expand Down
3 changes: 2 additions & 1 deletion node-src/tasks/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export const uploadStorybook = async (ctx: Context, task: Task) => {
const percentage = Math.round((progress / total) * 100);
task.output = uploading({ percentage }).output;

ctx.options.onTaskProgress?.({ ...ctx }, { progress, total, unit: 'bytes' });
ctx.options.experimental_onTaskProgress?.({ ...ctx }, { progress, total, unit: 'bytes' });
},
// Avoid spamming the logs with progress updates in non-interactive mode
ctx.options.interactive ? 100 : ctx.env.CHROMATIC_OUTPUT_INTERVAL
Expand All @@ -307,6 +307,7 @@ export const uploadStorybook = async (ctx: Context, task: Task) => {
};

export default createTask({
name: 'upload',
title: initial.title,
skip: (ctx: Context) => {
if (ctx.skip) return true;
Expand Down
1 change: 1 addition & 0 deletions node-src/tasks/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ export const verifyBuild = async (ctx: Context, task: Task) => {
};

export default createTask({
name: 'verify',
title: initial.title,
skip: (ctx: Context) => {
if (ctx.skip) return true;
Expand Down
Loading

0 comments on commit ab4a26e

Please sign in to comment.