Skip to content

Commit

Permalink
Merge pull request #755 from chromaui/tom/ap-3253-update-cli-to-be-ca…
Browse files Browse the repository at this point in the history
…llable-from-node-and-return-buildid

Add a node entry point
  • Loading branch information
tmeasday committed Jun 13, 2023
2 parents 329cf67 + 0046f76 commit 0e2f1ec
Show file tree
Hide file tree
Showing 285 changed files with 751 additions and 544 deletions.
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
action/main.js
dist
node_modules
subdir
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = {
},
overrides: [
{
files: ['*.json', 'isChromatic.js', 'isChromatic.mjs', 'isChromatic.cjs', '.eslintrc.cjs'],
files: ['*.json', 'isChromatic.mjs', 'isChromatic.js', 'isChromatic.cjs', '.eslintrc.cjs'],
parser: 'esprima',
rules: {
'@typescript-eslint/naming-convention': 'off',
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/smoke-test-node-api.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Smoke test via node api
on: push

jobs:
self-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
- run: yarn
- name: run chromatic via node
run: yarn ts-node ./scripts/run-via-node.ts
env:
LOG_LEVEL: debug
DEBUG: chromatic-cli
CHROMATIC_PROJECT_TOKEN: 47c20821d2c2
2 changes: 1 addition & 1 deletion .github/workflows/smoke-test-npx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
run: yarn && git status --porcelain
- name: prep package
run: ./scripts/rename.js storybook-chromatic
- run: yarn bundle:bin
- run: yarn build
- name: run chromatic
run: npx -p . chromatic --build-script-name build-test-storybook --exit-zero-on-changes --force-rebuild
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/smoke-test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
run: yarn
- name: prep package
run: node ./scripts/rename.js storybook-chromatic
- run: yarn bundle:bin
- run: yarn build
- name: run chromatic
run: npx -p . chromatic --build-script-name build-test-storybook --exit-zero-on-changes --force-rebuild
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/smoke-test-yarn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
with:
node-version: 16
- run: yarn
- run: yarn bundle:bin
- run: yarn build
- run: yarn chromatic --build-script-name build-test-storybook --exit-zero-on-changes --force-rebuild
env:
LOG_LEVEL: debug
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ node_modules
*.tgz
.editorconfig

action/main.js
storybook-static
subdir-static
test-storybook
chromatic-build-*.xml
chromatic-diagnostics.json
# the dist folder IS included so we can test every version in the CI without publishing
dist
bin
action
node
4 changes: 3 additions & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module.exports = {
stories: process.env.SMOKE_TEST ? ['../test-stories/*.stories.*'] : ['../bin-src/**/*.stories.*'],
stories: process.env.SMOKE_TEST
? ['../test-stories/*.stories.*']
: ['../node-src/**/*.stories.*'],
addons: ['@storybook/addon-viewport'],
features: {
postcss: false,
Expand Down
107 changes: 32 additions & 75 deletions action-src/main.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import { error, getInput, setFailed, setOutput } from '@actions/core';
import { context } from '@actions/github';
import { readFile } from 'jsonfile';
import pkgUp from 'pkg-up';
import { v4 as uuid } from 'uuid';
import path from 'path';

import getEnv from '../bin-src/lib/getEnv';
import { createLogger } from '../bin-src/lib/log';
import parseArgs from '../bin-src/lib/parseArgs';
import { runAll } from '../bin-src/main';
import { Context } from '../bin-src/types';
import { run as runNode } from '../node-src';

const maybe = (a: string, b: any = undefined) => {
if (!a) {
Expand Down Expand Up @@ -86,42 +79,6 @@ interface Output {
inheritedCaptureCount: number;
}

async function runChromatic(options): Promise<Output> {
const sessionId = uuid();
const env = getEnv();
const log = createLogger(sessionId, env);
const packagePath = await pkgUp(); // the user's own package.json
const packageJson = await readFile(packagePath);

const ctx: Partial<Context> = {
...parseArgs([]),
packagePath,
packageJson,
env,
log,
sessionId,
flags: options,
};
await runAll(ctx);

return {
// Keep this in sync with the configured outputs in action.yml
code: ctx.exitCode,
url: ctx.build?.webUrl,
buildUrl: ctx.build?.webUrl,
storybookUrl: ctx.build?.cachedUrl?.replace(/iframe\.html.*$/, ''),
specCount: ctx.build?.specCount,
componentCount: ctx.build?.componentCount,
testCount: ctx.build?.testCount,
changeCount: ctx.build?.changeCount,
errorCount: ctx.build?.errorCount,
interactionTestFailuresCount: ctx.build?.interactionTestFailuresCount,
actualTestCount: ctx.build?.actualTestCount,
actualCaptureCount: ctx.build?.actualCaptureCount,
inheritedCaptureCount: ctx.build?.inheritedCaptureCount,
};
}

async function run() {
const { sha, branch, slug, mergeCommit } = getBuildInfo(context) || {};
if (!sha || !branch || !slug) return;
Expand Down Expand Up @@ -167,37 +124,37 @@ async function run() {

process.chdir(path.join(process.cwd(), workingDir || ''));

const output = await runChromatic({
allowConsoleErrors: maybe(allowConsoleErrors, false),
autoAcceptChanges: maybe(autoAcceptChanges),
branchName: maybe(branchName),
buildScriptName: maybe(buildScriptName),
debug: maybe(debug),
diagnostics: maybe(diagnostics),
dryRun: maybe(dryRun),
exitOnceUploaded: maybe(exitOnceUploaded, false),
exitZeroOnChanges: maybe(exitZeroOnChanges, true),
externals: maybe(externals),
forceRebuild: maybe(forceRebuild),
fromCI: true,
ignoreLastBuildOnBranch: maybe(ignoreLastBuildOnBranch),
interactive: false,
only: maybe(only),
onlyChanged: maybe(onlyChanged),
onlyStoryFiles: maybe(onlyStoryFiles),
onlyStoryNames: maybe(onlyStoryNames),
preserveMissing: maybe(preserveMissing),
projectToken,
repositorySlug: maybe(repositorySlug),
skip: maybe(skip),
storybookBaseDir: maybe(storybookBaseDir),
storybookBuildDir: maybe(storybookBuildDir),
storybookConfigDir: maybe(storybookConfigDir),
traceChanged: maybe(traceChanged),
untraced: maybe(untraced),
workingDir: maybe(workingDir),
zip: maybe(zip, false),
junitReport: maybe(junitReport, false),
const output = await runNode({
flags: {
allowConsoleErrors: maybe(allowConsoleErrors, false),
autoAcceptChanges: maybe(autoAcceptChanges),
branchName: maybe(branchName),
buildScriptName: maybe(buildScriptName),
debug: maybe(debug),
diagnostics: maybe(diagnostics),
dryRun: maybe(dryRun),
exitOnceUploaded: maybe(exitOnceUploaded, false),
exitZeroOnChanges: maybe(exitZeroOnChanges, true),
externals: maybe(externals),
forceRebuild: maybe(forceRebuild),
ignoreLastBuildOnBranch: maybe(ignoreLastBuildOnBranch),
interactive: false,
only: maybe(only),
onlyChanged: maybe(onlyChanged),
onlyStoryFiles: maybe(onlyStoryFiles),
onlyStoryNames: maybe(onlyStoryNames),
preserveMissing: maybe(preserveMissing),
projectToken,
repositorySlug: maybe(repositorySlug),
skip: maybe(skip),
storybookBaseDir: maybe(storybookBaseDir),
storybookBuildDir: maybe(storybookBuildDir),
storybookConfigDir: maybe(storybookConfigDir),
traceChanged: maybe(traceChanged),
untraced: maybe(untraced),
zip: maybe(zip, false),
junitReport: maybe(junitReport, false),
},
});

Object.entries(output).forEach(([key, value]) => setOutput(key, String(value)));
Expand Down
5 changes: 0 additions & 5 deletions action-src/register.js
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
const Observable = require('zen-observable');

global.Observable = Observable;
require('any-observable/register')('global.Observable');

require('./main');
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,5 @@ outputs:
description: 'The number of inherited (not captured) snapshots (e.g. due to TurboSnap)'

runs:
main: action/main.js
main: action/register.js
using: node16
143 changes: 2 additions & 141 deletions bin-src/main.ts
Original file line number Diff line number Diff line change
@@ -1,144 +1,5 @@
import Listr from 'listr';
import { v4 as uuid } from 'uuid';
import readPkgUp from 'read-pkg-up';

import GraphQLClient from './io/GraphQLClient';
import HTTPClient from './io/HTTPClient';
import checkForUpdates from './lib/checkForUpdates';
import checkPackageJson from './lib/checkPackageJson';
import getEnv from './lib/getEnv';
import getOptions from './lib/getOptions';
import { createLogger } from './lib/log';
import NonTTYRenderer from './lib/NonTTYRenderer';
import parseArgs from './lib/parseArgs';
import { exitCodes, setExitCode } from './lib/setExitCode';
import { rewriteErrorMessage } from './lib/utils';
import { writeChromaticDiagnostics } from './lib/writeChromaticDiagnostics';
import getTasks from './tasks';
import { Context } from './types';
import fatalError from './ui/messages/errors/fatalError';
import fetchError from './ui/messages/errors/fetchError';
import graphqlError from './ui/messages/errors/graphqlError';
import invalidPackageJson from './ui/messages/errors/invalidPackageJson';
import missingStories from './ui/messages/errors/missingStories';
import noPackageJson from './ui/messages/errors/noPackageJson';
import runtimeError from './ui/messages/errors/runtimeError';
import taskError from './ui/messages/errors/taskError';
import intro from './ui/messages/info/intro';
import { endActivity } from './ui/components/activity';
import { run } from '../node-src';

export async function main(argv: string[]) {
const sessionId: string = uuid();
const env = getEnv();
const log = createLogger(sessionId, env);

const pkgInfo = await readPkgUp({ cwd: process.cwd() });
if (!pkgInfo) {
log.error(noPackageJson());
process.exit(253);
}

const { path: packagePath, packageJson } = pkgInfo;
if (typeof packageJson !== 'object' || typeof packageJson.scripts !== 'object') {
log.error(invalidPackageJson(packagePath));
process.exit(252);
}

// Warning: chromaui/action directly invokes runAll, so if new properties or arguments are added
// here, they must also be added to the GitHub Action.
const ctx: Partial<Context> = {
env,
log,
sessionId,
packageJson,
packagePath,
...parseArgs(argv),
};
await runAll(ctx);

log.info('');
process.exit(ctx.exitCode);
}

export async function runAll(ctx) {
setExitCode(ctx, exitCodes.OK);

ctx.http = (ctx.http as HTTPClient) || new HTTPClient(ctx);

// Run these in parallel; neither should ever reject
await Promise.all([runBuild(ctx), checkForUpdates(ctx)]);

if (ctx.exitCode === 0 || ctx.exitCode === 1) {
await checkPackageJson(ctx);
}

if (ctx.flags.diagnostics) {
await writeChromaticDiagnostics(ctx);
}
}

export async function runBuild(ctx: Context) {
ctx.log.info('');
ctx.log.info(intro(ctx));

try {
ctx.options = await getOptions(ctx);
} catch (e) {
ctx.log.info('');
ctx.log.error(fatalError(ctx, [e]));
setExitCode(ctx, exitCodes.INVALID_OPTIONS, true);
return;
}

try {
ctx.client = new GraphQLClient(ctx, `${ctx.env.CHROMATIC_INDEX_URL}/graphql`, {
headers: {
'x-chromatic-session-id': ctx.sessionId,
'x-chromatic-cli-version': ctx.pkg.version,
},
retries: 3,
});

try {
ctx.log.info('');
if (ctx.options.interactive) ctx.log.queue(); // queue up any log messages while Listr is running
const options = ctx.options.interactive ? {} : { renderer: NonTTYRenderer, log: ctx.log };
await new Listr(getTasks(ctx.options), options).run(ctx);
} catch (err) {
endActivity(ctx);
if (err.code === 'ECONNREFUSED' || err.name === 'StatusCodeError') {
setExitCode(ctx, exitCodes.FETCH_ERROR);
throw rewriteErrorMessage(err, fetchError(ctx, err));
}
if (err.name === 'GraphQLError') {
setExitCode(ctx, exitCodes.GRAPHQL_ERROR);
throw rewriteErrorMessage(err, graphqlError(ctx, err));
}
if (err.message.startsWith('Cannot run a build with no stories')) {
setExitCode(ctx, exitCodes.BUILD_NO_STORIES);
throw rewriteErrorMessage(err, missingStories(ctx));
}
throw rewriteErrorMessage(err, taskError(ctx, err));
} finally {
// Handle potential runtime errors from JSDOM
const { runtimeErrors, runtimeWarnings } = ctx;
if ((runtimeErrors && runtimeErrors.length) || (runtimeWarnings && runtimeWarnings.length)) {
ctx.log.info('');
ctx.log.error(runtimeError(ctx));
}

ctx.log.flush();
}
} catch (error) {
const errors = [].concat(error); // GraphQLClient might throw an array of errors

if (errors.length && !ctx.userError) {
ctx.log.info('');
ctx.log.error(fatalError(ctx, errors));
}

if (!ctx.exitCode) {
setExitCode(ctx, exitCodes.UNKNOWN_ERROR);
}
}
return run({ argv });
}
4 changes: 0 additions & 4 deletions bin-src/register.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#!/usr/bin/env node
/* eslint-disable global-require */
const Observable = require('zen-observable');

global.Observable = Observable;
require('any-observable/register')('global.Observable');

require('dotenv').config();

Expand Down
Loading

0 comments on commit 0e2f1ec

Please sign in to comment.