UNPKG

3.68 kBJavaScriptView Raw
1import { readFile } from 'jsonfile';
2import Listr from 'listr';
3import pkgUp from 'pkg-up';
4import { v4 as uuid } from 'uuid';
5
6import GraphQLClient from './io/GraphQLClient';
7import checkForUpdates from './lib/checkForUpdates';
8import checkPackageJson from './lib/checkPackageJson';
9import getEnv from './lib/getEnv';
10import getOptions from './lib/getOptions';
11import { createLogger } from './lib/log';
12import NonTTYRenderer from './lib/NonTTYRenderer';
13import parseArgs from './lib/parseArgs';
14import { rewriteErrorMessage } from './lib/utils';
15import getTasks from './tasks';
16import fatalError from './ui/messages/errors/fatalError';
17import fetchError from './ui/messages/errors/fetchError';
18import missingStories from './ui/messages/errors/missingStories';
19import runtimeError from './ui/messages/errors/runtimeError';
20import taskError from './ui/messages/errors/taskError';
21import intro from './ui/messages/info/intro';
22
23export async function main(argv) {
24 const sessionId = uuid();
25 const env = getEnv();
26 const log = createLogger(sessionId, env);
27 const packagePath = await pkgUp(); // the user's own package.json
28 const packageJson = await readFile(packagePath);
29
30 // Warning: chromaui/action directly invokes runAll, so if new properties or arguments are added
31 // here, they must also be added to the GitHub Action.
32 const ctx = { env, log, sessionId, packageJson, packagePath, ...parseArgs(argv) };
33 await runAll(ctx);
34
35 log.info('');
36 process.exit(ctx.exitCode);
37}
38
39export async function runAll(ctx) {
40 // Run these in parallel; neither should ever reject
41 await Promise.all([runBuild(ctx), checkForUpdates(ctx)]);
42
43 if (!ctx.exitCode || ctx.exitCode === 1) {
44 await checkPackageJson(ctx);
45 }
46}
47
48export async function runBuild(ctx) {
49 ctx.log.info('');
50 ctx.log.info(intro(ctx));
51
52 try {
53 ctx.options = await getOptions(ctx);
54 } catch (e) {
55 ctx.log.info('');
56 ctx.log.error(e.message);
57 ctx.exitCode = 254;
58 return;
59 }
60
61 try {
62 ctx.client = new GraphQLClient({
63 uri: `${ctx.env.CHROMATIC_INDEX_URL}/graphql`,
64 headers: {
65 'x-chromatic-session-id': ctx.sessionId,
66 'x-chromatic-cli-version': ctx.pkg.version,
67 },
68 retries: 3,
69 log: ctx.log,
70 });
71
72 try {
73 ctx.log.info('');
74 if (ctx.options.interactive) ctx.log.queue(); // queue up any log messages while Listr is running
75 const options = ctx.options.interactive ? {} : { renderer: NonTTYRenderer, log: ctx.log };
76 await new Listr(getTasks(ctx.options), options).run(ctx);
77 } catch (err) {
78 if (err.code === 'ECONNREFUSED' || err.name === 'StatusCodeError') {
79 ctx.log.info('');
80 ctx.log.error(fetchError(ctx, err));
81 return;
82 }
83 if (err.message.startsWith('Cannot run a build with no stories')) {
84 throw rewriteErrorMessage(err, missingStories(ctx));
85 }
86 throw rewriteErrorMessage(err, taskError(ctx, err));
87 } finally {
88 // Handle potential runtime errors from JSDOM
89 const { runtimeErrors, runtimeWarnings } = ctx;
90 if ((runtimeErrors && runtimeErrors.length) || (runtimeWarnings && runtimeWarnings.length)) {
91 ctx.log.info('');
92 ctx.log.error(runtimeError(ctx));
93 }
94
95 ctx.log.flush();
96 if (ctx.stopApp) ctx.stopApp();
97 if (ctx.closeTunnel) ctx.closeTunnel();
98 }
99 } catch (error) {
100 const errors = [].concat(error); // GraphQLClient might throw an array of errors
101
102 if (errors.length && !ctx.userError) {
103 ctx.log.info('');
104 ctx.log.error(fatalError(ctx, errors));
105 }
106
107 // Not sure what exit code to use but this can mean error.
108 if (!ctx.exitCode) ctx.exitCode = 255;
109 }
110}