UNPKG

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